diff --git a/.github/workflows/jekyll-docker.yml b/.github/workflows/jekyll-docker.yml new file mode 100644 index 0000000..9160615 --- /dev/null +++ b/.github/workflows/jekyll-docker.yml @@ -0,0 +1,35 @@ +name: Jekyll site CI + +on: + push: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Build the site in the jekyll/builder container + run: | + docker run \ + -v ${{ github.workspace }}:/srv/jekyll -v ${{ github.workspace }}/_site:/srv/jekyll/_site \ + jekyll/builder:latest /bin/bash -c "apk update && apk add graphicsmagick && chmod -R 777 /srv/jekyll && jekyll build" + - name: Rsync Deployments Action + # You may pin to the exact commit or the version. + # uses: Burnett01/rsync-deployments@2651e3eecb4ea772cbe952695d04952e92027b4f + uses: Burnett01/rsync-deployments@5.2.1 + with: + # The switches + switches: -r --delete-after + # The local path + path: _site/ + # The remote path + remote_path: ~/www/ + # The remote host + remote_host: ulises.us + # The remote user + remote_user: ulisesus + # The remote key + remote_key: ${{ secrets.GREENGEEKS_KEY }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b60333a --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +_site +.sass-cache +.jekyll-metadata +.jekyll-cache +vendor +.bundle +node_modules +.DS_Store +._asset_bundler_cache +Gemfile.lock diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..c026f36 --- /dev/null +++ b/Gemfile @@ -0,0 +1,29 @@ +source "https://rubygems.org" + +# Hello! This is where you manage which Jekyll version is used to run. +# When you want to use a different version, change it below, save the +# file and run `bundle install`. Run Jekyll with `bundle exec`, like so: +# +# bundle exec jekyll serve +# +# This will help ensure the proper Jekyll version is running. +# Happy Jekylling! +# gem "jekyll", ">= 3.6.3" +gem "jekyll", "~> 4.0.0" + + + +# This is the default theme for new Jekyll sites. You may change this to anything you like. +# gem "minima", "~> 2.0" +gem "neat" +gem "mini_magick" +gem "json" +# If you want to use GitHub Pages, remove the "gem "jekyll"" above and +# uncomment the line below. To upgrade, run `bundle update github-pages`. +# gem "github-pages", group: :jekyll_plugins + +# If you have any plugins, put them here! +group :jekyll_plugins do + # gem "jekyll-feed", "~> 0.6" + gem "jemoji" +end diff --git a/README.md b/README.md new file mode 100644 index 0000000..1a384d0 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +``` + + + __ __ + | \| \ + __ __ | $$ \$$ _______ ______ _______ +| \ | \| $$| \ / \ / \ / \ +| $$ | $$| $$| $$| $$$$$$$| $$$$$$\| $$$$$$$ +| $$ | $$| $$| $$ \$$ \ | $$ $$ \$$ \ +| $$__/ $$| $$| $$ _\$$$$$$\| $$$$$$$$ _\$$$$$$\ + \$$ $$| $$| $$| $$ \$$ \| $$ + \$$$$$$ \$$ \$$ \$$$$$$$ \$$$$$$$ \$$$$$$$ + __ __ +| \ | \ +| $$____ ______ ______ | $$ __ _______ +| $$ \ / \ / \ | $$ / \ / \ +| $$$$$$$\| $$$$$$\| $$$$$$\| $$_/ $$| $$$$$$$ +| $$ | $$| $$ | $$| $$ | $$| $$ $$ \$$ \ +| $$__/ $$| $$__/ $$| $$__/ $$| $$$$$$\ _\$$$$$$\ +| $$ $$ \$$ $$ \$$ $$| $$ \$$\| $$ + \$$$$$$$ \$$$$$$ \$$$$$$ \$$ \$$ \$$$$$$$ + + + + +``` + +:alien: Repository for [ulises.us](http://ulises.us) :alien: diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..ac86592 --- /dev/null +++ b/_config.yml @@ -0,0 +1,119 @@ +# Ulises.us Jekyll Config +# +# bundle exec jekyll [command] + +# includes settings for: +# - prose.io +# - minimagick + +# Site settings + +title: ULISES +email: hello@ulises.us +description: > + Ulises / Books / Curation +baseurl: "" +url: "" # the base hostname & protocol for your site, e.g. http://example.com +github_username: hello-ulises + +# Build settings +markdown: kramdown +highlighter: rouge +incremental: false + +gems: + - jekyll-feed + - jemoji + - jekyll-minimagick + +exclude: + - Gemfile + - Gemfile.lock + - package.json + - package-lock.json + - vendor + - .asset-cache + - .bundle + - .jekyll-assets-cache + - .sass-cache + - gulpfile.js + - node_modules + - README.md + - components + +encoding: "utf-8" +markdown_ext: "md" + +kramdown: + input: GFM + hard_wrap: false + smart_quotes: lsquo,rsquo,ldquo,rdquo + +sass: + sass_dir: _sass + style: compressed + +mini_magick: + resize: + source: assets/img + destination: assets/img + resize: "600x>" + +prose: + rooturl: '_posts' + media: 'assets/img' + ignore: + - index.md + - _config.yml + - /_layouts + - /_includes + metadata: + _posts: + - name: "title" + field: + element: "text" + placeholder: "enter post title" + help: This will appear as the post title + label: "title" + - name: "date" + field: + element: "text" + help: Date of post affects in which order posts appear + value: CURRENT_DATETIME + - name: "event_date" + field: + element: "text" + help: If applicable, enter date and time of event as it should appear in the text of the post + - name: "layout" + field: + element: "hidden" + value: "post" + - name: "categories" + field: + element: "select" + label: "column" + placeholder: "choose column" + options: + - name: "left" + value: "left" + - name: "right" + value: "right" + - name: "tags" + field: + element: "multiselect" + label: "tags" + placeholder: "choose or add tags" + alterable: true + options: + - name: "sticky" + value: "sticky" + - name: "active-voice" + value: "active-voice" + - name: "intimacy" + value: "intimacy" + - name: "published" + field: + element: "checkbox" + label: "published" + help: Check if you'd like to see this post published to the public site + value: false diff --git a/_includes/google-analytics.html b/_includes/google-analytics.html new file mode 100644 index 0000000..eb2a692 --- /dev/null +++ b/_includes/google-analytics.html @@ -0,0 +1,11 @@ + + diff --git a/_includes/head.html b/_includes/head.html new file mode 100644 index 0000000..eb77268 --- /dev/null +++ b/_includes/head.html @@ -0,0 +1,27 @@ + + + + + + {% if page.title %}{{ page.title | escape }}{% else %}{{ site.title | escape }}{% endif %} + + + + + + + + + + + + + + + + + {% if jekyll.environment == 'production' and site.google_analytics %} + {% include google-analytics.html %} + {% endif %} + + diff --git a/_includes/header.html b/_includes/header.html new file mode 100644 index 0000000..d1d4381 --- /dev/null +++ b/_includes/header.html @@ -0,0 +1,55 @@ + diff --git a/_includes/pasp.html b/_includes/pasp.html new file mode 100644 index 0000000..3cd6580 --- /dev/null +++ b/_includes/pasp.html @@ -0,0 +1,15 @@ +

PUBLISHING
AS PRACTICE:

+ + + + + +
+ +
+ + {% assign pasp = site.posts | where: 'tags', 'pasp' %} + {% for post in pasp %} + {% include post-single.html %} + {% endfor %} +
diff --git a/_includes/post-single.html b/_includes/post-single.html new file mode 100644 index 0000000..175a52e --- /dev/null +++ b/_includes/post-single.html @@ -0,0 +1,23 @@ +
+ +
+ + {{ post.title | prepend: "## " | markdownify }} + + + + {% if post.event_date %} + {{ post.event_date | prepend: "

" | append: "

" }} + {% endif %} + +
+ +
+ {% if post.summary %} + {{ post.summary }} + {% else %} + {{ post.content}} + {% endif %} +
+ +
\ No newline at end of file diff --git a/_includes/splash.html b/_includes/splash.html new file mode 100644 index 0000000..9d19013 --- /dev/null +++ b/_includes/splash.html @@ -0,0 +1,45 @@ +
+ +{% assign p1 = "publishing as
practice:" %} +{% assign p2 = "a three part
publishing residency" %} + + + +
+

+hardworking
goodlooking +

+ +

+martine syms /
dominica +

+ +

+bidoun +

+
+ +
+
+ +{% for i in (1..200) %} + +{{ p1 }} + +{% endfor %} + +
+ +
+ +{% for i in (1..200) %} + +{{ p2 }} + +{% endfor %} + +
+
+
+ +
\ No newline at end of file diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 0000000..f0dbdc8 --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,19 @@ + + + +{% include head.html %} + + + +
{{ content }}
+ + + + + + + diff --git a/_layouts/page.html b/_layouts/page.html new file mode 100644 index 0000000..01e4b2a --- /dev/null +++ b/_layouts/page.html @@ -0,0 +1,14 @@ +--- +layout: default +--- +
+ +
+

{{ page.title | escape }}

+
+ +
+ {{ content }} +
+ +
diff --git a/_layouts/post.html b/_layouts/post.html new file mode 100644 index 0000000..bfe2e6e --- /dev/null +++ b/_layouts/post.html @@ -0,0 +1,17 @@ +--- +layout: default +--- +
+ +
+ +

{{ page.title | escape }}

+ + +
+ +
+ {{ content }} +
+ +
diff --git a/_plugins/jekyll_minimagick.rb b/_plugins/jekyll_minimagick.rb new file mode 100644 index 0000000..ce74c7d --- /dev/null +++ b/_plugins/jekyll_minimagick.rb @@ -0,0 +1,80 @@ +require 'mini_magick' + +module Jekyll + module JekyllMinimagick + + class GeneratedImageFile < Jekyll::StaticFile + # Initialize a new GeneratedImage. + # +site+ is the Site + # +base+ is the String path to the + # +dir+ is the String path between and the file + # +name+ is the String filename of the file + # +preset+ is the Preset hash from the config. + # + # Returns + def initialize(site, base, dir, name, preset) + @site = site + @base = base + @dir = dir + @name = name + @dst_dir = preset.delete('destination') + @src_dir = preset.delete('source') + @commands = preset + @relative_path = File.join(*[@dir, @name].compact) + @extname = File.extname(@name) + end + + # Obtains source file path by substituting the preset's source directory + # for the destination directory. + # + # Returns source file path. + def path + File.join(@base, @dir.sub(@dst_dir, @src_dir), @name) + end + + # Use MiniMagick to create a derivative image at the destination + # specified (if the original is modified). + # +dest+ is the String path to the destination dir + # + # Returns false if the file was not modified since last time (no-op). + def write(dest) + dest_path = destination(dest) + + return false if File.exist? dest_path and !modified? + self.class.mtimes[path] = mtime + + FileUtils.mkdir_p(File.dirname(dest_path)) + image = ::MiniMagick::Image.open(path) + image.combine_options do |c| + @commands.each_pair do |command, arg| + c.send command, arg + end + end + image.write dest_path + + true + end + + end + + class MiniMagickGenerator < Generator + safe true + + # Find all image files in the source directories of the presets specified + # in the site config. Add a GeneratedImageFile to the static_files stack + # for later processing. + def generate(site) + return unless site.config['mini_magick'] + + site.config['mini_magick'].each_pair do |name, preset| + Dir.chdir preset['source'] do + Dir.glob(File.join("**", "*.{png,jpg,jpeg,gif}")) do |source| + site.static_files << GeneratedImageFile.new(site, site.source, preset['destination'], source, preset.clone) + end + end + end + end + end + + end +end diff --git a/_posts/2016-11-08-we-are-open.md b/_posts/2016-11-08-we-are-open.md new file mode 100644 index 0000000..10e4aaa --- /dev/null +++ b/_posts/2016-11-08-we-are-open.md @@ -0,0 +1,11 @@ +--- +layout: post +title: 'Hello, Opening Party' +date: 'Fri Nov 11 2016 19:00:00 GMT-0500 (EST)' +event_date: November 12, 2016, 6–9PM +categories: left +published: true +--- + +![peace_small.png]({{site.baseurl}}/assets/img/peace_small.png) + diff --git a/_posts/2016-11-12-active-voice.md b/_posts/2016-11-12-active-voice.md new file mode 100644 index 0000000..06f57d7 --- /dev/null +++ b/_posts/2016-11-12-active-voice.md @@ -0,0 +1,56 @@ +--- +title: No. 1 Active Voice +date: 2016-11-12 +event_date: November 12, 2016 through January 22, 2017 +layout: post +categories: left +published: true +--- + +Active Voice considers the voice in relation to listening, language, and political agency through a series of programs, artworks, readings, events, and curated publications from contributors Mark Beasley, Hannah Black, and Steffani Jemison. Active Voice seeks to address the performative and embodied potential of the voice and its ability to reify and limit political and social realities. + +## Contributors + +### Steffani Jemison + +Steffani Jemison presents her 2014 two-channel sound piece, "Same Time," a reprisal of a speech delivered in 1970 by Black Panther Party founder Huey P. Newton that has been reinterpreted by Brooklyn-based R&B group Sidetrack Boyz as a vocal improvisation. + +### Hannah Black + +Hannah Black presents a selection of recent video works – including "Intensive Care/Hot New Track," "Fall of Communism," and "My Bodies" – that consider pop vocals as a space to explore violence, power, and pluralism. + +### Mark Beasley +Re-Voice Reading Room + +A curated selection of books and records on the theme of voice + + +January 10, 2017, 6:30PM–8PM +January 17, 2017, 6:30PM–8PM +Mark Beasley: Re-Voice Reading Room + +Mark Beasley presents, *Re-Voice*, a curated selection of books and records on the theme of voice. These events are the first in a new reading group series from Ulises entitled "Dear Reader". These discussions aim to open up and invite conversation on excerpts from Mark's list. + + +## Twelve Books & Seven Records: Re-Voice +A curated selection of books and records on the theme of voice, by Mark Beasley + +1. Ashley, Robert, "Perfect Lives: An Opera, Burning Books," New York, 1991 +2. Barthes, Roland, and Stephen Heath, "Image, Music, Text," New York, Hill and Wang, 1977 +3. Beasley, Mark, "Hey Hey Glossolalia: Exhibiting the Voice," New York, Creative Time Books, 2008 +4. Butler, Judith, "Excitable Speech (A Politics of the Performative)," Routledge, New York and London, 1997 +5. Connor, Steven, "Dumbstruck, (A Cultural History of Ventriloquism)," Oxford University Press, 2000 +6. Dietrich, Ralf, "Robert Ashley: Outside of Time," Germany, Musik Texte, 2009 +7. Dolar, Mladen, "A Voice and Nothing More," (Short Circuits), The MIT Press, Cambridge, MA, 2006 +8. Heller-Roazen, Daniel, "Dark Tongues: The Art of Rogues and Riddlers," Brooklyn, New York, Zone Books, 2013 +9. Mudrian, Albert, "Choosing Death: The improbable history of Death Metal and Grindcore," Los Angeles, Feral House, 2004 +10. Nancy, Jean-Luc, "Listening," Fordham University Press, USA, 2007 +11. Neumark, Norie, "Voice, (Vocal Aesthetics in Digital Arts and Media)," The MIT Press, Cambridge, 2010 +12. Weiss, Allen S., "Breathless," (Sound Recording, Disembodiment, and The Transformation of Lyrical Nostalgia), Wesleyan University Press, Middletown, CT, 2002 +13. Lincoln, Abbey, "We Insist!" (Freedom Now Suite), Max Roach, 1960 +14. Ashley, Robert, "The Wolfman," New York, Lovely Music, 1964 / 2003 +15. Ono, Yoko, "Fly," 1971 +16. La Barbara, Joan, "Voice is the Original Instrument," New York, Wizard Records, 1976 (Re-released in 2016 on Arc Light Editions) +17. Cabaret Voltaire, "Extended Play," Rough Trade Records, 1978 +18. Napalm Death, "Scum," Birmingham, Earache Records, 1987 +19. Big Legs, "Big Legs," Junior Aspirin Records, 2015 \ No newline at end of file diff --git a/_posts/2016-11-19-virtual-reading.md b/_posts/2016-11-19-virtual-reading.md new file mode 100644 index 0000000..29dea83 --- /dev/null +++ b/_posts/2016-11-19-virtual-reading.md @@ -0,0 +1,14 @@ +--- +date: '2016-12-14 23:11 -0500' +event_date: December 18, 2016, 4–5:30PM +layout: post +published: false +title: 'Active Voice: Screen Time with Hannah Black' +--- + +![dd2.png]({{site.baseurl}}/assets/img/dd2.png) + + +Join Ulises for a reading with artist and writer Hannah Black. Black, a current contributor to the first curatorial season of Ulises, Active Voice, will read via Skype from a selection of her recent writings. + +Active Voice considers the voice in relation to listening, language, and political agency through a series of programs, artworks, readings, events, and curated publications from contributors Mark Beasley, Hannah Black, and Steffani Jemison. As a contributor to Active Voice, Hannah Black presents recent video works on view which consider pop vocals as a space to explore violence, power, and pluralism. diff --git a/_posts/2016-12-09-odds-and-ends.md b/_posts/2016-12-09-odds-and-ends.md new file mode 100644 index 0000000..a395cdc --- /dev/null +++ b/_posts/2016-12-09-odds-and-ends.md @@ -0,0 +1,10 @@ +--- +layout: post +date: '2016-12-09 15:30 -0500' +published: true +title: 'Odds & Ends Book Fair' +categories: left +event_date: 'December 9, 2016, 11:30AM–4:30PM' +--- + +Ulises is heading to New Haven for the day to participate in the [Odds & Ends Art Book Fair](http://artgallery.yale.edu/calendar/events/book-fair-odds-and-ends-art-booksbook-arts-today) hosted by Yale University Art Gallery. diff --git a/_posts/2016-12-10-post-template.md b/_posts/2016-12-10-post-template.md new file mode 100644 index 0000000..2b8eff7 --- /dev/null +++ b/_posts/2016-12-10-post-template.md @@ -0,0 +1,40 @@ +--- +date: '2016-12-10 13:37 -0500' +layout: post +published: false +categories: left +tags: + - migrations +title: post template +--- +**note that the first line of a post will appear center-aligned because the post expects it to be a date!** + +*a template for what a post can look like* + +If you'd like to know more about [Markdown](http://daringfireball.net/projects/markdown/), here's the original description of the project. An interesting take on single-source publishing and a brand of functional minimalism. + +For more tips/trick on how to format in Markdown, I often refer to [this cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet). + +:pizza: Also, [emoji support](http://www.webpagefx.com/tools/emoji-cheat-sheet/) :pizza: + + +(headings) +# h1 +## h2 +### h3 + +(ul) +- one +- two +- three + +(ol) +1. one +1. two +1. three + + +(horizontal rule) +--- + +![odds_ends_2016_1600x1600.jpg]({{site.baseurl}}/assets/img/odds_ends_2016_1600x1600.jpg) \ No newline at end of file diff --git a/_posts/2016-12-24-holiday-hours.md b/_posts/2016-12-24-holiday-hours.md new file mode 100644 index 0000000..3ff561d --- /dev/null +++ b/_posts/2016-12-24-holiday-hours.md @@ -0,0 +1,14 @@ +--- +date: '2016-12-24 09:53 -0500' +layout: post +published: false +title: Holiday Hours +--- +We will be open Saturday December 24 from 12PM–4PM and closed December 25 through January 2. +Happy Holidays and see you in the New Year! + +![UlisesHolidayHours.jpg]({{site.baseurl}}/assets/img/UlisesHolidayHours.jpg) + + + + diff --git a/_posts/2017-01-03-dear-reader-a-voice-and-nothing-more.md b/_posts/2017-01-03-dear-reader-a-voice-and-nothing-more.md new file mode 100644 index 0000000..335e932 --- /dev/null +++ b/_posts/2017-01-03-dear-reader-a-voice-and-nothing-more.md @@ -0,0 +1,20 @@ +--- +date: '2017-01-03 22:33 -0500' +event_date: Tuesday, January 10, 2017, 6:30-8PM +layout: post +published: true +title: 'Dear Reader: A Voice and Nothing More' +categories: left +--- + +![10-carrion_thumb-2.jpg]({{site.baseurl}}/assets/img/10-carrion_thumb-2.jpg) + +Join Ulises for a book discussion on Mladen Dolars's text "A Voice and Nothing More." This event is the first in a new reading group series from Ulises entitled "Dear Reader." The reading for this session is the introduction to "A Voice and Nothing More" found in the link below. + +["A Voice and Nothing More," Introduction](https://drive.google.com/file/d/0By5QSqc6j12OTElYZ3ZRVlZVaWM/view){:target="_blank"} + +"A Voice and Nothing More" by Mladen Dolar is one of the publications included in "Twelve Books & Seven Records: Re-voice," a presentation of books and albums selected by curator Mark Beasley as his contribution to Ulises's curatorial season Active Voice. + +Active Voice considers the voice in relation to listening, language, and political agency through a series of programs, artworks, readings, and selected publications from contributors Mark Beasley, Hannah Black, and Steffani Jemison. + +Facilitating the discussion is Hammam Aldouri. Hammam Aldouri is an independent scholar who holds a PhD in philosophy from the CRMEP, Kingston University and a Helena Rubinstein Fellowship in Critical Studies from the Whitney Museum of American Art, Independent Study Program. His writing has been published in Radical Philosophy, Detroit Research and Field Journal. He is currently a contributor to the Philadelphia based online art magazine the Artblog. \ No newline at end of file diff --git a/_posts/2017-01-13-dear-reader-excitable-speech.md b/_posts/2017-01-13-dear-reader-excitable-speech.md new file mode 100644 index 0000000..7e213ed --- /dev/null +++ b/_posts/2017-01-13-dear-reader-excitable-speech.md @@ -0,0 +1,22 @@ +--- +date: '2017-01-13 22:34 -0500' +event_date: Tuesday, January 17, 2017, 6:30–8PM +layout: post +published: true +title: 'Dear Reader: Excitable Speech' +categories: left +--- + +![15895272_1251954841554748_1400330800993685810_n.jpg]({{site.baseurl}}/assets/img/15895272_1251954841554748_1400330800993685810_n.jpg) + +Join Ulises for a reading group discussion led by Maria Murphy on Judith Butler's text “Excitable Speech: A Politics of the Performative.” This session's reading will focus on Chapter One of “Excitable Speech” entitled, “Burning Acts, Injurious Speech,” found in the link below. + +[Butler, Judith. Chapter One. "Excitable Speech: A Politics of the Performative." New York: Routledge, 1997. 43-69.](https://drive.google.com/file/d/0BwPEQQWlPfvacmxaTHFfc3dWc0tRVzFrRWg4Vzhqc2hUalRv/view){:target="_blank"} + +As part of the discussion, Murphy will perform “The Production of Voice,” a short spoken-word piece for voice and voice processor and John Cage's “Aria” (1958), originally written for interpretation by Cathy Berberian. + +“Excitable Speech” by Judith Butler is included in “Twelve Books & Seven Records: Re-voice,” a presentation of books and albums selected by curator Mark Beasley as his contribution to Ulises’s curatorial season Active Voice. + +Active Voice considers the voice in relation to listening, language, and political agency through a series of programs, artworks, readings, and selected publications from contributors Mark Beasley, Hannah Black, and Steffani Jemison. + +Maria Murphy is a PhD candidate in musicology at the University of Pennsylvania. Her research considers the relationship between music technologies and body politics through the work of multimedia artists Laurie Anderson, Yoko Ono, and Karen Finley. In her dissertation, Maria maps how these artists participated in a particular mode of aesthetic activism, which took part in biopolitical shifts concerning the circulation and industrialization of information, the production of healthy and sickly bodies, and the political fictions of gender and sexuality during a precarious time for public health and social hygiene under Ronald Reagan’s administration. Maria is also interested in developing creative spaces for hands-on research. She is the co-founder of [Listening (to) Cyborgs: A Media Archaeology Workshop on Sound Technologies](http://listeningtocyborgs.com){:target="_blank"}. diff --git a/_posts/2017-01-14-screen-time-with-hannah-black.md b/_posts/2017-01-14-screen-time-with-hannah-black.md new file mode 100644 index 0000000..ec1f0d4 --- /dev/null +++ b/_posts/2017-01-14-screen-time-with-hannah-black.md @@ -0,0 +1,15 @@ +--- +date: '2017-01-14 19:09 -0500' +event_date: December 18, 2016, 4-5:30PM +layout: post +published: false +title: Screen Time with Hannah Black +categories: left +--- + +![fall-of-communism.png]({{site.baseurl}}/assets/img/fall-of-communism.png) + + +Artist and writer Hannah Black will read via the internet from a selection of her recent writings. Black is a current contributor to the first curatorial season of Ulises, Active Voice; her work is assembled from pop music and autobiographical fragments and draws on feminist, communist and black radical thought. + +Image: Hannah Black,"Fall of Communism," 2014, video still. diff --git a/_posts/2017-02-08-launch-party-for-quarter-no-2-intimacy.md b/_posts/2017-02-08-launch-party-for-quarter-no-2-intimacy.md new file mode 100644 index 0000000..8453699 --- /dev/null +++ b/_posts/2017-02-08-launch-party-for-quarter-no-2-intimacy.md @@ -0,0 +1,17 @@ +--- +layout: post +date: '2017-02-10 18:19 -0500' +published: true +title: Launch Party Quarter No. 2 Intimacy +categories: left +tags: + - intimacy +event_date: 'Saturday, February 11, 2017' +--- + +![15. HAYES-2.jpg]({{site.baseurl}}/assets/img/15. HAYES-2.jpg) + + +[RSVP](https://www.facebook.com/events/604532113075419/){:target="_blank"} + +Image: Sharon Hayes, "May 1st," 2012. 5 Letterpress prints (framed), 14.5 x 19.75 in. Edition of 5 + 2 AP diff --git a/_posts/2017-02-08-no-2-intimacy.md b/_posts/2017-02-08-no-2-intimacy.md new file mode 100644 index 0000000..dd44ee6 --- /dev/null +++ b/_posts/2017-02-08-no-2-intimacy.md @@ -0,0 +1,67 @@ +--- +title: No. 2 Intimacy +date: 2017-02-08 01:34 -0500 +event_date: February 11 through June 11, 2017 +layout: post +categories: left +tags: + - intimacy +published: true +--- + +In this quarter, Ulises considers intimacy through a close-knit constellation of topics, ranging from proximity and privacy to love, friendship, sex, and sexuality. Through a season of artworks, programs, and explorations, Ulises seeks to offer space for artists, thinkers, and communities of care to interrogate our role as social and civic participants, engage notions of inclusion and belonging, and discuss and employ affect, empathy, and love-based politics. Artist Sharon Hayes, scholar Lauren Berlant, and independent publishing imprint Badlands Unlimited provide principal contributions, with additional contributors extending these ideas and communities over a period of three months. + + +## Contributors + + +### Sharon Hayes + +"May 1st," 2012 +Five Letterpress prints (framed) +36.8 x 50.2 cm +14 1/2 x 19 3/4 in +Edition of 5 + 2 AP + +In addition to "May 1st," Hayes presents a new public work entitled, "Beyond the moon is Lesbos, you told me," a series of texts posted in public space in Philadelphia addressesing both the present political moment and the linguistic and psychic terrain of the outburst. + +### Badlands Unlimited, "New Lovers" + +A paperback erotica fiction series inspired by Maurice Girodias’s legendary Olympia Press, Badlands Unlimited's "New Lovers" series features the raw and uncut writings of authors new to the erotica genre. Each novella in the "New Lovers" series is an independent story of about 12,000-18,000 words in length with its own unique take on relationships, intimacy, and sex, as well as the complexities that bedevil contemporary life and culture today. + +- Wednesday Black, “How To Train Your Virgin” +- Lilith Wes, “We Love Lucy” +- Andrea McGinty, “God, I Don’t Even Know Your Name” +- Lex Brown, “My Wet Hot Drone Summer” +- Al Bedell, “I Would Do Anything For Love” +- Cara Benedetto, “Burning Blue” +- Tamara Faith Berger, “Kuntalini” +- Bettina Davis, “One Valencia Lane” +- Larissa Pham, “Fantasian” +- "New Lovers" Reading Event with Larissa Pham and Al Bedell, March 4th, 6:30pm + + +### Lauren Berlant + +Selected Readings on Intimacy: + +1. James Baldwin, All works +1. Roland Barthes, “A Lover’s Discourse," "Incidents," and "Camera Lucida” +1. Leo Bersani and Adam Phillips, “Intimacies” +1. Svetlana Boym, “Diasporic Intimacy” +1. Veena Das, “Life and Words: Violence and the Descent into the Ordinary” +1. Bracha Ettinger, All works +1. Deborah Gould, “Moving Politics” +1. Donna Haraway, “The Companion Species Manifesto” +1. Bhanu Kapil, All works +1. Chris Kraus, “I Love Dick” +1. Annette Kuhn, “Family Secrets” +1. Kiese Laymon, “Long Division” and “How to Slowly Kill Yourself and Others in America” +1. Toni Morrison, All works +1. Beatriz Preciado, “Testo Junkie” +1. Elspeth Probyn, “Outside Belonging” +1. Christina Sharpe, “Monstrous Intimacies” +1. Carolyn Steedman, “Landscape for a Good Woman” +1. Kathleen Stewart, “Ordinary Affects” +1. Jalal Toufic, “Undying Love”, or “Love Dies” +1. Patricia Williams, “On Being an Object of Property” diff --git a/_posts/2017-02-09-screen-time-with-hannah-black.md b/_posts/2017-02-09-screen-time-with-hannah-black.md new file mode 100644 index 0000000..ae008e1 --- /dev/null +++ b/_posts/2017-02-09-screen-time-with-hannah-black.md @@ -0,0 +1,18 @@ +--- +layout: post +date: '2016-12-18 17:43 -0500' +event_date: 'Sunday, December 18, 2016, 4PM' +published: true +title: Screen Time with Hannah Black +categories: left +tags: + - active-voice +--- + +![fall-of-communism.png]({{site.baseurl}}/assets/img/fall-of-communism.png) + +Artist and writer Hannah Black. Black, will read via Skype from a selection of her recent writings. As a contributor to Active Voice, Hannah Black presents recent video works — including “Intensive Care/Hot New Track,” “Fall of Communism,” and “My Bodies” – that consider pop vocals as a space to explore violence, power, and pluralism. + +Image: Hannah Black, "Fall of Communism," 2014, video still + +View the full ["Fall of Communism" video](https://vimeo.com/110016117) diff --git a/_posts/2017-02-09-steffani-jemison-in-conversation.md b/_posts/2017-02-09-steffani-jemison-in-conversation.md new file mode 100644 index 0000000..b8ac13d --- /dev/null +++ b/_posts/2017-02-09-steffani-jemison-in-conversation.md @@ -0,0 +1,14 @@ +--- +layout: post +date: '2016-12-02 17:39 -0500' +event_date: Friday, December 2, 2016, 6PM +published: true +title: Steffani Jemison in Conversation +categories: left +tags: + - active-voice +--- +![Steffani Jemison Event.jpg]({{site.baseurl}}/assets/img/Steffani Jemison Event.jpg) + + +Steffani Jemison presents her 2014 two-channel sound piece, "Same Time," a reprisal of a speech delivered in 1970 by Black Panther Party founder Huey P. Newton that has been reinterpreted by Brooklyn-based R&B group Sidetrack Boyz as a vocal improvisation. Her presentation will be followed by a conversation with Steffani and artist David Hartt. diff --git a/_posts/2017-02-12-info.md b/_posts/2017-02-12-info.md new file mode 100644 index 0000000..328267f --- /dev/null +++ b/_posts/2017-02-12-info.md @@ -0,0 +1,27 @@ +--- +title: info +date: 2017-02-22 09:58 -0500 +layout: post +tags: + - info +published: true +--- +Location\ +1400 North American Ave. Philly, PA. (at Icebox Project Space) + +Hours\ +Friday & Saturday 12-6pm; Sunday 12-4pm + +Interested in consigning your publication with Ulises? \ +[Submit your book for review](https://formfacade.com/public/112249199778780145474/all/form/1FAIpQLSe1SAV81fyD0-95YBEViGFzc2j3Bo9deIDyjHSNJV4hPIYSVQ) + +About\ +Ulises is a bookshop and project space dedicated to artists’ books and independent art publications that explores the relationship between publics and publications. We provide an inventory of titles not widely distributed in the United States on contemporary art, graphic design, art theory, architecture, criticism, curatorial practice, and adjacent fields. We support people who make books and expand the boundaries of what art publishing can be. + +Hosting projects, exhibitions, and residencies, Ulises’s open-ended programming explores publishing as an incubator for new forms of artistic, editorial, curatorial, and pedagogical practice. Ulises sees the democratic potential of publishing as a vehicle for activism, education, assembly, and exchange. + +The name Ulises is a tribute to the work and legacy of Ulises Carrión, a Mexican-born poet, conceptualist, and avant-garde artist who was an early pioneer and theorist of the artist’s book, and the founder of the Amsterdam based bookshop *Other Books and So* (1975–78). + +Ulises was founded in 2016 by Nerissa Cooney, Lauren Downing, Joel Evey, Kayla Romberger, Gee Wesley, and Ricky Yanas. Additional contributors include Tim Belknap, Jody Harrington, and Nabil Kashyap. + +Sign up for our news and give us a follow ↓ \ No newline at end of file diff --git a/_posts/2017-02-13-nato-thompson-culture-as-weapon.md b/_posts/2017-02-13-nato-thompson-culture-as-weapon.md new file mode 100644 index 0000000..8c1c4c8 --- /dev/null +++ b/_posts/2017-02-13-nato-thompson-culture-as-weapon.md @@ -0,0 +1,15 @@ +--- +layout: post +date: '2017-02-12' +published: true +title: 'Nato Thompson: Culture As Weapon' +categories: left +event_date: 'Sunday, February 19, 2017, 4PM' +--- +![Nato-3.jpg]({{site.baseurl}}/assets/img/Nato-3.jpg) + +Book talk with Nato Thompson on his new book,"Culture as Weapon: The Art of Influence in Everyday Life." Thompson is the artistic director of the nonprofit arts organization Creative Time, which commissions and supports socially engaged works of art. + +"Culture as Weapon" is a spirited and insightful examination of how, over the past century, corporations, politicians, nonprofits, and activists alike have embraced the power of creativity to shape public opinion, for good and for ill. Thompson simultaneously investigates the way artists have reacted to this cultural transformation, from Andy Warhol's prescient Pop Art to Dread Scott Tyler's provocative installations to Suzanne Lacy's social interventions. As he puts it, “the world has witnessed the realization of the age-old avant-garde demand that art become part of the everyday.” + +[RSVP](https://www.facebook.com/events/678431575669743/) diff --git a/_posts/2017-02-21-title-magazine-relaunch-party.md b/_posts/2017-02-21-title-magazine-relaunch-party.md new file mode 100644 index 0000000..bfe1d6d --- /dev/null +++ b/_posts/2017-02-21-title-magazine-relaunch-party.md @@ -0,0 +1,14 @@ +--- +layout: post +date: '2017-02-21' +published: true +title: Title Magazine Relaunch Party +categories: left +--- +![TitleLaunch.jpg]({{site.baseurl}}/assets/img/TitleLaunch.jpg) + +Since 2012, Title has been a fixture in the Philadelphia art world as an unaffiliated platform for art writing. Beginning in 2017, they are establishing a new structure in pursuit of broader, more conceptually-driven goals for content. Title Magazine’s new editorial team — Lindsay Buchman, Samantha Mitchell, Kaitlin Pomerantz, Meredith Sellers, and Bailey Sheehan — invites you to join in celebrating their relaunch at Ulises. Brunch cocktails and light snacks will be available! + +[RSVP](https://www.facebook.com/events/376630539361171/) + +Image: Isabel Lederman diff --git a/_posts/2017-02-26--new-lovers-erotica-reading-conversation.md b/_posts/2017-02-26--new-lovers-erotica-reading-conversation.md new file mode 100644 index 0000000..be8dc85 --- /dev/null +++ b/_posts/2017-02-26--new-lovers-erotica-reading-conversation.md @@ -0,0 +1,22 @@ +--- +layout: post +date: '2017-02-26 15:06 -0500' +published: true +title: '"New Lovers" Erotica Reading' +event_date: 'Saturday, March 4, 2017, 6:30–8PM' +categories: left +tags: + - intimacy +--- +![badlands_no5_i_would_do_anything_for_love_2.jpg]({{site.baseurl}}/assets/img/badlands_no5_i_would_do_anything_for_love_2.jpg) + +Authors Al Bedell and Larissa Pham will be reading excerpts from their short erotic fiction published by Badlands Unlimited and part of the "New Lovers" series. Each story has its own unique take on relationships, intimacy, and sex, as well as the complexities that bedevil contemporary life and culture today. + +[Join the intimate evening](https://www.facebook.com/events/326139811117166/) – drinks and light refreshments will be served. + +[Al Bedell, “I Would Do Anything For Love”](https://badlandsunlimited.com/books/new-lovers-5-i-would-do-anything-for-love) +Al Bedell is a writer who splits her time between New York and Los Angeles. Her writing explores quotidian trauma and the contemporary female condition. She studied Philosophy at the University of Hartford. + +[Larissa Pham, “Fantasian”](https://badlandsunlimited.com/books/new-lovers-9-fantasian) +Larissa Pham is a writer living in Brooklyn. She has written for Adult, Guernica, The Nation and Nerve. Pham studied painting and art history at Yale University. + diff --git a/_posts/2017-03-07-love-optimized-workshop-and-pop-up-show.md b/_posts/2017-03-07-love-optimized-workshop-and-pop-up-show.md new file mode 100644 index 0000000..77fead2 --- /dev/null +++ b/_posts/2017-03-07-love-optimized-workshop-and-pop-up-show.md @@ -0,0 +1,42 @@ +--- +layout: post +date: '2017-03-07 22:12 -0500' +published: true +title: 'Love, Optimized: Workshop and Pop-Up Show' +categories: left +tags: + - intimacy +event_date: 'Saturday, March 18, 2017' +--- +![love-optimized-workshop-animation.gif]({{site.baseurl}}/assets/img/love-optimized-workshop-animation.gif) + + +Workshop: Saturday 2–5pm +Limited capacity: Sign up at [loveoptimizedworkshop.eventbrite.com](https://loveoptimizedworkshop.eventbrite.com) + +Pop-Up Show: Saturday 5pm–7pm + Sunday 12–6pm +Features inventions blueprinted at the workshop. +Open to all: [RSVP for the Pop-Up Reception](https://www.facebook.com/events/800056596808318/) + +Welcome to a world of problems, solved. + +_Love, Optimized_ is a multimedia experience by Object Solutions, a fictional company that envisions the high-tech future of romance—with a dose of dark humor. + +In the _Love, Optimized_ workshop, you become the inventor. Guided by our laboratorians, you partner up and draw blueprints for new technologies to solve everyday love troubles. The afternoon’s inventions become a pop-up show at Ulises, where visitors are invited to imagine the future of love—optimized. + +Our aim is to provoke pressing questions about intimacy and innovation. By co-creating a vision of tech-assisted love, we engage in what Anthony Dunne calls “design for debate,” where we move away from thinking about technological _applications_ to technological _implications_. We invite you to consider the possibilities and limitations of a future where intimacy is administered and supervised by consumer products. + +_Love, Optimized_ is a partnership between Ernesto D. Morales and Shelly Ronen. + +For richer details, visit [objectsolutions.net/love](http://objectsolutions.net/love) + +For more intimate contact, join our mailing list at +[objectsolutions.net/mail](http://www.objectsolutions.net/mail) + +See the workshop overview + images: +[How to Design the Future of Love](http://www.objectsolutions.net/blog/workshop-designing-future-love/) + +See what participants have devised: +- [Surveillant clothing and immersive dreams](http://www.objectsolutions.net/blog/objects-of-affection-episode-1/) +- [Precoital pinpricks and the foul stench of breakups](http://www.objectsolutions.net/blog/objects-of-affection-episode-2/) +- [Emotional dinnerware and connected underwear](http://www.objectsolutions.net/blog/objects-of-affection-episode-3/) diff --git a/_posts/2017-03-15-screening-the-politics-of-intimacy.md b/_posts/2017-03-15-screening-the-politics-of-intimacy.md new file mode 100644 index 0000000..d24146d --- /dev/null +++ b/_posts/2017-03-15-screening-the-politics-of-intimacy.md @@ -0,0 +1,21 @@ +--- +layout: post +date: '2017-03-15 22:06 -0400' +published: true +title: 'Screening: The Politics of Intimacy' +tags: + - intimacy +event_date: 'Tuesday, March 21, 2017, 6:30 – 8:30PM' +categories: left +--- +![politics-of-intimacy.jpg]({{site.baseurl}}/assets/img/politics-of-intimacy.jpg) + +Please join Ulises, in partnership with Moore College of Art and Deisgn, for a screening of "The Politics of Intimacy" (Julie Gustafson, 1972, 52 minutes) and "Now" (Lynda Benglis, 1973, 12 minutes) with an introduction by Jesse Pires, Program Curator at International House Philadelphia. + +These two feminist works exemplify the intimacy and immediacy of emergent video technologies in the early 1970s. Both videos employ “close-up” framing, a cinematic device that more intimately connects a viewer to an onscreen subject. In "The Politics of Intimacy," various women, representing a wide range of ages and social and economic backgrounds, openly discuss their sexual feelings and behaviors on topics ranging from orgasm to masturbation. The tape unfolds in a manner that resembles a candid conversion not unlike those of women’s consciousness-raising groups from the era. With Now, Benglis intensifies the relationship between viewer and screen as she interacts with various prerecorded versions of herself. The mediated intimacy of the artist speaking across time and space is downright haunting and foreshadows a future where screens and devices would become preferred modes of connection. + +[RSVP](https://www.facebook.com/events/1598045313558488/?active_tab=about) + +[International House Philadelphia](http://ihousephilly.org/about) + +[Moore College of Art and Design](http://moore.edu/) diff --git a/_posts/2017-03-20-your-filename.md b/_posts/2017-03-20-your-filename.md new file mode 100644 index 0000000..a757894 --- /dev/null +++ b/_posts/2017-03-20-your-filename.md @@ -0,0 +1,8 @@ +--- +layout: post +date: '2017-03-20 00:12 -0400' +published: true +title: '' +categories: left +--- +![DSCF5080.jpeg]({{site.baseurl}}/assets/img/DSCF5080.jpeg) diff --git a/_posts/2017-03-22--hypernormalisation-screening.md b/_posts/2017-03-22--hypernormalisation-screening.md new file mode 100644 index 0000000..853dde2 --- /dev/null +++ b/_posts/2017-03-22--hypernormalisation-screening.md @@ -0,0 +1,19 @@ +--- +layout: post +date: '2017-03-22 22:53 -0400' +published: true +title: '"Hyper Normalization" Screening' +categories: left +event_date: 'Friday, March 31, 2017, 7:30PM' +--- +![TITLE CARD.png]({{site.baseurl}}/assets/img/TITLE CARD.png) + + +Please join Ulises for a screening of “Hyper Normalization” (Adam Curtis, 2016, 166 minutes) with an introduction by Ulises member and Philly-based designer, Joel Evey. Followed by drinks and mingling. + +Adam Curtis explains how, at a time of confusing and inexplicable world events, politicians and the people they represent have retreated in to a damaging, & over-simplified version of the world. + +[on ideas and consequences] Well, a lot of people go on about how I'm a leftist, but I'm not really, because I believe that ideas have consequences. And why I like people like Weber [German sociologist Max Weber (1864-1920)] is because they are challenging what I see as that crude left-wing vulgar Marxism that says that everything happens because of economic forces within society, that we are just surfing, our ideas are just expressions-froth on the deep currents of history, which is really driven by economics. I've never believed that. Of course, economic forces have a great effect on us. But actually, people's ideas have enormous consequences. And to be honest, if you had to reduce what I do, I spend my whole time just looking at how ideas have consequences, not necessarily what the promoters of them intended, because I think that's a really big thing in our time. I came into writing and describing and filming the world at the very moment that those old left-wing certainties were beginning to collapse, certainties that said somehow progress and modernity were on a inevitable path towards a particular destination in history. But it was also equally obvious to me the right-wing reaction-where you just bring a market force in to create a form of stability that goes nowhere-was equally not going to work. And I became interested in examining how ideas have led us to this position in ways that those who had the ideas didn't really intend. People like Weber who were, in a sense, conservative sociologists of the late nineteenth century were looking at the consequences of rationality. At how scientific ideas were used by those in power in modern society-and what the consequences then were. I think this is still incredibly important to look at today. [2012] +— [Adam Curtis on IMDB](http://www.imdb.com/name/nm0193231/bio) + +[RSVP](https://www.facebook.com/events/1808171052837511/) diff --git a/_posts/2017-03-22-dear-reader-with-ban-en-banlieu.md b/_posts/2017-03-22-dear-reader-with-ban-en-banlieu.md new file mode 100644 index 0000000..321ccc7 --- /dev/null +++ b/_posts/2017-03-22-dear-reader-with-ban-en-banlieu.md @@ -0,0 +1,22 @@ +--- +layout: post +date: '2017-03-22 23:08 -0400' +published: true +title: 'Dear Reader: "Ban en Banlieue"' +categories: left +tags: + - intimacy +event_date: 'Tuesday, March 28, 2017, 6:30PM – 8:30PM' +--- +![Ban1.jpg]({{site.baseurl}}/assets/img/Ban1.jpg) + + +"Will you give a hand to Ban? Do you have a sentiment, do you have class? Let me tell you before you extend yourself that Ban is disgusting. Let me tell you that Ban is a difficult person to love, full of transience. I could tell you things about Ban." + +Join Ulises for a reading group discussion and writing session led by Becky Huff Hunter on Bhanu Kapil's book "Ban en Banlieue" —partly a response to Theresa Hak Kyung Cha's murder—which struggles to memorialize the rape of a young Indian girl walking home alone during a race riot. This session will focus on roughly the first half of the book, found in the link below. + +["Ban en Banlieu" PDF](https://drive.google.com/file/d/0B_P5glJ74tP7djN1NUNib2R5ZUE/view) + +Bring a notepad and pen in order to participate in writing exercises that draw upon the book's themes. As the discussion will partly be discussing interpersonal violence, please help us maintain a safe space by being mindful and considerate of others. + +Becky Huff Hunter is a writer and editor, who has recently written on Philadelphia's contemporary art in "Artforum," "Frieze," and "Art Papers." She previously organized the Writing Art and Life reading/writing groups at the Institute of Contemporary Art and Kelly Writers House, University of Pennsylvania, where she is also a trained Anti-Violence Advocate. diff --git a/_posts/2017-04-06-screening-lawrence-abu-hamdan.md b/_posts/2017-04-06-screening-lawrence-abu-hamdan.md new file mode 100644 index 0000000..f0cc7ca --- /dev/null +++ b/_posts/2017-04-06-screening-lawrence-abu-hamdan.md @@ -0,0 +1,21 @@ +--- +layout: post +date: '2017-04-06 11:57 -0400' +published: true +title: 'Screening: Lawrence Abu Hamdan' +tags: + - intimacy +categories: left +event_date: 'Friday, April 14, 2017, 7PM – 9PM' +--- +![KHSG_11_Lawrence_Abu_Hamdan_2015.jpeg]({{site.baseurl}}/assets/img/KHSG_11_Lawrence_Abu_Hamdan_2015.jpeg) + +In response to Ulises’ current quarterly, [Lawrence Abu Hamdan](http://lawrenceabuhamdan.com/) presents two works that cast a shadow on the theme of intimacy. "Saydnaya (the missing 19db)," recently commissioned for Sharjah Biennial 13, and "Language Gulf in the Shouting Valley," (2013) contour intimacies of violence, separation, and conflict. The works communicate, in whispers and shouts, bonds nevertheless formed and performed in difficult – murderous – terrains: the prison, the courtroom, and the border. Venturing considerations of intimacy in relation to community, citizenship, and the state, this event also aims to question some of the presumed conditions of intimacy: proximity, disclosure, transparency, reciprocal knowledge, truth. This event is co-organized with Ulises by Kirsten Gill, who will also give an introduction. [RSVP](https://www.facebook.com/events/633462733505988/) + +Lawrence Abu Hamdan, "Language Gulf in the Shouting Valley," 2013, +Digital video, 14' + +Lawrence Abu Hamdan, "Saydnaya (the missing 19db)," 2017, +Stereo audio, 12' + +Image: Lawrence Abu Hamdan, "Language Gulf in the Shouting Valley," 2013. Installation view at Kunsthalle St Gallen. Photo by Stefan Jaggi diff --git a/_posts/2017-04-12-the-third-rail-issue-10-launch-event.md b/_posts/2017-04-12-the-third-rail-issue-10-launch-event.md new file mode 100644 index 0000000..340aa4e --- /dev/null +++ b/_posts/2017-04-12-the-third-rail-issue-10-launch-event.md @@ -0,0 +1,19 @@ +--- +layout: post +date: '2017-04-12 18:32 -0400' +published: true +title: The Third Rail Issue 10 Philadelphia Launch +tags: + - intimacy +categories: left +event_date: 'Saturday, April 15, 2017, 7PM–9PM' +--- +![TTR-Issue-10d.gif]({{site.baseurl}}/assets/img/TTR-Issue-10d.gif) + +Please join Ulises this Saturday for the Philadelphia launch of the newest issue of The Third Rail. The launch will feature a short screening program of videos connected to Issue 10 and Ulises' quarterly theme, Intimacy. Jonathan Thomas, editor of The Third Rail, will give a brief introduction. Drinks and light refreshments will be available. + +At 8pm we will screen a teaser from Adam Khalil and Zack Khalil's second feature film, "Empty Metal," co-directed with Barry James Sweitzer, followed by Mati Diop and Manon Lutanie's "Liberian Boy" (2015), and two shorts by Alexander Kluge: "BLIND LOVE / Jean-Luc Godard: My mother had only seen silent films!," and "TSCHAK TSCHAK BOING / Love in a Space Suit" (both 2001). + +[Issue 10](http://thirdrailquarterly.org/) of The Third Rail features an in-depth interview with writer, filmmaker, and television pioneer Alexander Kluge by Jonathan Thomas, in which Kluge shares his theory of montage and constellational filmmaking, discusses his move from cinema into television, and unpacks his principle of the city; psychoanalyst Jamieson Webster recalls her first dreams on the analytic couch; actress and filmmaker Mati Diop and independent publisher Manon Lutanie present a four-minute dance film; film critics Cristina Álvarez López and Adrian Martin reflect on Isabelle Huppert’s performance style, both in print and with an audiovisual essay online; filmmaker Sky Hopinka discusses indigenous poetics, language revitalization, and experimental modes of documentary filmmaking with filmmakers Adam Khalil and Zack Khalil, and shares a video online; poet Anne Boyer writes on a rebellion against images; experimental flutist and composer Barbara Held is interviewed by Alexandra Alisauskas and Godfre Leung and discusses breath as a medium, composer-interpreter-audience relations, and her approach to the indeterminate scores of Alvin Lucier and Yasunao Tone; chef Michelle Gayer offers a tool for fighting fascism; and there are artist projects by John Fleischer and Sara Greenberger Rafferty. + +[The Third Rail](http://thirdrailquarterly.org/#information) is a free nonprofit periodical devoted to a discussion of modern and contemporary art, politics, philosophy, and culture, featuring critical essays and reviews, interviews, literary arts, and artist projects. Based in Minneapolis, The Third Rail is an editorially independent affiliate of The Brooklyn Rail. diff --git a/_posts/2017-04-18-dear-reader-on-diasporic-intimacy.md b/_posts/2017-04-18-dear-reader-on-diasporic-intimacy.md new file mode 100644 index 0000000..a3df095 --- /dev/null +++ b/_posts/2017-04-18-dear-reader-on-diasporic-intimacy.md @@ -0,0 +1,24 @@ +--- +layout: post +date: '2017-04-18 10:50 -0400' +published: true +title: 'Dear Reader: On Diasporic Intimacy' +tags: + - intimacy +categories: left +event_date: 'Tuesday, April 25, 2017, 6:30PM–8PM' +--- +![0425-DearReader.jpg]({{site.baseurl}}/assets/img/0425-DearReader.jpg) + +"Diasporic intimacy does not promise an unmediated emotional fusion, but only a precarious affection-- no less deep, yet aware of its transience." - Svetlana Boym + +Join Ulises for a group discussion facilitated by Jennifer Wilson on Svetlana Boym's article "On Diasporic Intimacy: Ilya Kabakov's Installations and Immigrant Homes." + +Please find the reading in the following link: +[Boym, Svetlana. “On Diasporic Intimacy: Ilya Kabakov's Installations and Immigrant Homes.” Critical Inquiry, vol. 24, no. 2, 1998, pp. 498–524.](https://drive.google.com/open?id=0B_P5glJ74tP7WUp5eXB1bG1LcUx1YXlpVVF0dnU1cmlZSk1J) + +Jennifer Wilson is a Postdoctoral Fellow in the Department of Slavic Languages and Literatures at the University of Pennsylvania where she is currently working on her first book, "Radical Chastity: Abstinence and the Political Imagination in Nineteenth Century Russia." From 2015-2016, she participated in the Penn Humanities Forum on "Sex." Her writings on literary culture, Russia, and politics have appeared in The New Yorker, The Atlantic, The Los Angeles Review of Books, and Al Jazeera America, among others. You can follow her on Twitter at @JenLouiseWilson. + +Svetlana Boym's article "On Diasporic Intimacy: Ilya Kabakov's Installations and Immigrant Homes" is one of the texts included in "Selected Readings on Intimacy," a presentation of books and articles choosen by scholar Lauren Berlant as her contribution to Ulises's curatorial season "Intimacy." + +[RSVP for Dear Reader: On Diasporic Intimacy](https://www.facebook.com/events/1896355483973082/) diff --git a/_posts/2017-04-18-paper-cuts-reading.md b/_posts/2017-04-18-paper-cuts-reading.md new file mode 100644 index 0000000..8bfc22f --- /dev/null +++ b/_posts/2017-04-18-paper-cuts-reading.md @@ -0,0 +1,25 @@ +--- +layout: post +date: '2017-04-18 10:09 -0400' +published: false +title: 'Paper Cuts Reading ' +event_date: 'Saturday, April 22, 2016, 7PM' +categories: left +tags: + - migrations +--- + + +continuing to test + +![ULISES CARD3.jpg]({{site.baseurl}}/assets/img/ULISES CARD3.jpg) + +[Paper Cuts](http://clocktower.org/series/paper-cuts), the zine, DIY, and small press reading program on [Clocktower Radio](http://clocktower.org/radio), is taking the show on the road with a series of events at bookstores and alternative spaces. Each event will feature writers, zinesters, artists, and performers who typically share their work in print, on paper, and in small editions. Think of it as a traveling micro-zine tour. Come to hear great work and talk with the readers about zines and small press publications. + +Readers: Arno Mokros, J Pascoe, Alex Smith + +[Arno Mokros](http://arno-press.tumblr.com/zines) is a queer writer based in Queens, NY. He writes cultural criticism, creative non-fiction, and sometimes poetry. In 2016, he co-founded Little Pharma and completed a residency at the Vermont Studio Center. + +[J Pascoe](http://jpascoe.com/home.html) is an artist living and working in Philadelphia, Pennsylvania. Pascoe received her BFA in Intermedia from Pacific Northwest College of Art, Portland, Oregon (2004) and her MFA in Book Arts and Printmaking from the University of the Arts, Philadelphia (2013). She recently completed a residency focusing on printmaking and book arts at Skaftfell Center for Visual Art in Seyðisfyörður, Iceland and was previously a Visiting Artist at George Mason University, Fairfax, Virginia and the Spring 2016 Artist in Residence at Rowan University, Glassboro, New Jersey. + +[Alex Smith](http://metropolarity.net/tag/alex-smith/): the science-fiction of fashion, the punk rock of soothsayers, the tri-chromatic lamp of the universe diff --git a/_posts/2017-05-04-high-tide-zine-release.md b/_posts/2017-05-04-high-tide-zine-release.md new file mode 100644 index 0000000..4dfb671 --- /dev/null +++ b/_posts/2017-05-04-high-tide-zine-release.md @@ -0,0 +1,19 @@ +--- +layout: post +date: '2017-05-04 20:30 -0400' +published: true +title: High Tide Zine Release +categories: left +event_date: 'Sunday, May 7, 2017, 4:00–6:00PM' +tags: + - intimacy +--- +![18274858_1358834817533416_4529206522363639203_n.jpg]({{site.baseurl}}/assets/img/18274858_1358834817533416_4529206522363639203_n.jpg) + +Join us at Ulises to celebrate the release of 3 new zines. "Leap of Faith" by Isaac Tin Wei Lin, "Two Way Mirror" by Clark Mizono, and "The Grand Inquisitor" by Fyodor Dostoyevsky with illustrations by Zoe Axelrod and Geoffrey KixMiller, are the first publications produced by High Tide and we are excited to share them with you. + +Isaac Tin Wei Lin explores the realm where representation and buzzing abstraction meet. His surfaces are often densely covered in calligraphic, brushed and hand-drawn patterns that express both the logic and complexity of written language. Cartoon figures, often in the form of cats and dogs, make appearances, sometimes as larger-than-life-size cut-outs covered in pattern themselves. + +Clark Mizono, is an artist and freelance photographer living and working in New York City. + +High Tide is an artist-run gallery and project space located in the Kensington neighborhood of Philadelphia. Through formal exhibitions, performances, workshops and experimental programming, High Tide seeks to maintain a critical dialogue between artists and our local and global communities. diff --git a/_posts/2017-05-04-philadelphia-art-book-fair.md b/_posts/2017-05-04-philadelphia-art-book-fair.md new file mode 100644 index 0000000..2e81c3c --- /dev/null +++ b/_posts/2017-05-04-philadelphia-art-book-fair.md @@ -0,0 +1,19 @@ +--- +layout: post +date: '2017-05-04 20:15 -0400' +published: true +title: Philadelphia Art Book Fair +categories: left +tags: + - intimacy +--- +![16998808_1089515417860400_7652733978941710275_n-680x680.jpg]({{site.baseurl}}/assets/img/16998808_1089515417860400_7652733978941710275_n-680x680.jpg) + +Friday, May 5: 12:00pm-8:00pm + +Saturday, May 6: 10:00am-6:00pm + +We are excited to be participating in the Philadelphia Art Book Fair, co-presented by Philadelphia Photo Arts Center and The Print Center. It is a two-day event showcasing 70 plus exhibitors, from art book publishers to individual artists and institutions, local, national and international. + +Location: Twelve 27, 1227 N. 4th Street, Phila, PA +Entrance to the Philadelphia Art Book Fair is free, open to the public and fully accessible. diff --git a/_posts/2017-05-15-becky-suss-book-release.md b/_posts/2017-05-15-becky-suss-book-release.md new file mode 100644 index 0000000..3d9c4cf --- /dev/null +++ b/_posts/2017-05-15-becky-suss-book-release.md @@ -0,0 +1,19 @@ +--- +layout: post +date: '2017-05-15 10:42 -0400' +published: true +title: Becky Suss Book Release +event_date: 'Saturday, May 20, 2017, 3–5PM' +categories: left +--- +![becksuss-book-release.jpg]({{site.baseurl}}/assets/img/becksuss-book-release.jpg) + +Join Ulises for a [book launch](https://www.facebook.com/events/475958902735805/) with artist Becky Suss. Enjoy libations, snacks and company celebrating the release of the ICA exhibition catalogue "Beck Suss." + +In the fall of 2015, Suss presented selections from her most recent body of work in her first solo museum exhibition curated by ICA's Laporte Associate Curator, Kate Kraczon. Released in 2017, the fully illustrated catalogue for this exhibition includes an extended interview of Suss by Kate Kraczon. + +"Meditative, large-scale paintings augmented by smaller studies in oil and ceramic reimagine the domestic spaces of her relatives with a focus on her late grandparents’ mid-century suburban home. The flattened architecture and exaggerated perspective of Suss’s canvases memorialize their collected art and objects through an intimate, archeological process that opens familial narrative to questions of class, politics, and religion." + +Becky Suss was born in 1980 in Philadelphia, Pennsylvania, where she is currently based. She received an MFA from the University of California, Berkeley, a BA from Williams College, and in 2013 attended the Skowhegan School of Painting and Sculpture. In addition to ICA Philadelphia, Suss’ work has been exhibited at the Woodmere Art Museum, Pennsylvania, the Berkeley Art Museum, California, and The Berman Museum at Ursinus College, Pennsylvania, as well as at storied Philadelphia artist collectives Vox Populi and Space 1026, of which she is a former member. She is represented by Jack Shainman Gallery and Fleisher/Ollman Gallery. Her solo exhibition Homemaker is currently on view at Jack Shainman Gallery through June 3rd. + +Image: Becky Suss, "1919 Chestnut (Three Cities, The Mother, Kiddush Hashem, Salvation, The Apostle, Mary, Nazarene)," 2015 \ No newline at end of file diff --git a/_posts/2017-05-21-artist-run-reading-spaces-panel-book-display.md b/_posts/2017-05-21-artist-run-reading-spaces-panel-book-display.md new file mode 100644 index 0000000..91d668f --- /dev/null +++ b/_posts/2017-05-21-artist-run-reading-spaces-panel-book-display.md @@ -0,0 +1,24 @@ +--- +layout: post +date: '2017-05-21 20:23 -0400' +published: true +title: 'Artist-Run Reading Spaces, Panel & Book Display' +event_date: 'Sunday, June 4, 3:30–5PM' +categories: left +--- +![18556623_310192286079730_3304069030822008828_o.jpg]({{site.baseurl}}/assets/img/18556623_310192286079730_3304069030822008828_o.jpg) + +[Artist-Run Reading Spaces](https://www.facebook.com/events/170205546844757/?acontext=%7B%22ref%22%3A%223%22%2C%22ref_newsfeed_story_type%22%3A%22regular%22%2C%22feed_story_type%22%3A%22361%22%2C%22action_history%22%3A%22null%22%7D) is part of BABZ FAIR 2017 Extended Program Series +[Knockdown Center](https://knockdown.center/), 52-19 Flushing Ave, Queens, New York 11378 + +From 1975 to 1978 in Amsterdam, Ulises Carrión operated Other Books and So, an artist-run bookstore and exhibition space dedicated to artists’ books and ephemera, which served as a key point of interchange between Latin American and European artists’ publishing communities. Drawing upon this example, this discussion brings together the founders of artist-run bookstores, libraries, and reading rooms. Ideas of circulation, access, and “making public” intersect both libraries and experimental publishing practices, and artist-run reading spaces offer alternative ways of actualizing these ideas outside of institutional paradigms. More than distribution points for texts, they function as social spaces of reading. Panelists will join in a 90-minute discussion of their projects, to be accompanied by a casual book display including items selected by the presenters and items from MoMA Library. + +Panelists: +- Gee Wesley, Ulises, Philadelphia +- Rachel Valinsky, Wendy's Subway, Brooklyn, NY +- David Richardson, Dispersed Holdings, NYC +- Kimi Hanauer & Bomin Jeon, Press Press, Baltimore +- Devin N Morris, Brown Paper Zine Fair, 3 DOT ZINE, Brooklyn, NY + + +Moderator: Sarah Hamerman, Artist Book Cataloger, MoMA Library diff --git a/_posts/2017-06-23-no-03-migrations.md b/_posts/2017-06-23-no-03-migrations.md new file mode 100644 index 0000000..dad730b --- /dev/null +++ b/_posts/2017-06-23-no-03-migrations.md @@ -0,0 +1,20 @@ +--- +title: "Opening: No. 3 Migrations " +date: 2017-06-23 11:24 -0400 +event_date: Saturday, July 1, 2017, 3–7PM +layout: post +categories: left +tags: + - migrations +published: true +--- +![Superunknown 2.jpg]({{site.baseurl}}/assets/img/Superunknown 2.jpg) + + +Please join Ulises in celebrating the launch of our third quarterly season, "Migrations," on Saturday, July 1 from 3-7PM. [RSVP](https://www.facebook.com/events/655994014599294/?acontext=%7B%22source%22%3A5%2C%22page_id_source%22%3A1129359703814263%2C%22action_history%22%3A[%7B%22surface%22%3A%22page%22%2C%22mechanism%22%3A%22main_list%22%2C%22extra_data%22%3A%22%7B%5C%22page_id%5C%22%3A1129359703814263%2C%5C%22tour_id%5C%22%3Anull%7D%22%7D]%2C%22has_source%22%3Atrue%7D) + +“Migrations” considers how artists, thinkers, and whole communities engage narratives of movement and traversal, sanctuary and refuge. Through contributions from artists [Marwa Arsanios](http://www.mor-charpentier.com/artist/marwa-arsonios/), [Tania Bruguera](http://www.taniabruguera.com/cms/), [Banu Cennetoğlu](http://rodeo-gallery.com/artists/banu-cennetoglu/), and [Xaviera Simmons](https://davidcastillogallery.com/artist/xaviera-simmons/), Ulises will explore the poetics of migration and trouble our notions of origin and boundaries. + +Image: Xaviera Simmons, "Superunknown (Alive In The)" (detail), 2010. +42 C-prints mounted on sintra with brace, each photo 20 x 30 in. Edition of 3. +Installation view Perez Art Museum Miami in “Poetics of Relation” (2015), Courtesy David Castillo Gallery diff --git a/_posts/2017-06-27-no-3-migrations.md b/_posts/2017-06-27-no-3-migrations.md new file mode 100644 index 0000000..90c557a --- /dev/null +++ b/_posts/2017-06-27-no-3-migrations.md @@ -0,0 +1,39 @@ +--- +title: No. 3 Migrations +date: 2017-06-27 23:21 -0400 +event_date: July 1 through October 1, 2017 +layout: post +categories: left +tags: + - migrations +published: true +--- +"Migrations” considers how artists, thinkers, and whole communities engage narratives of movement and traversal, sanctuary and refuge. Through video, photography, and readings from artists [Marwa Arsanios](http://www.mor-charpentier.com/artist/marwa-arsonios/), [Tania Bruguera](http://www.taniabruguera.com/cms/), [Banu Cennetoğlu](http://rodeo-gallery.com/artists/banu-cennetoglu/), and [Xaviera Simmons](https://davidcastillogallery.com/artist/xaviera-simmons/), Ulises will explore the poetics of migration and trouble our notions of origin and boundaries. Further contributions of workshops, screenings, lectures, and presentations will survey and remap these themes throughout the course of the season. + +## Contributors + +### Marwa Arsanios + +“Falling Is Not Collapsing, Falling Is Extending,” 2016 +Digital video, color, sound +22:34 min. + +“Resilient Weeds,” 2016 +Pen on paper +Dimensions variable + +### Banu Cennetoğlu + +“The List” is a document that contains the information of known refugees, asylum seekers, and migrants who have died within, or on the borders of Europe since 1993. The data is compiled and updated each year by UNITED for Intercultural Action. Since 2006, in collaboration with art workers and institutions, Banu Cennetoğlu maintains up-to-date and translated versions of “The List” for public display and dissemination. + +### Tania Bruguera + +"Selected Readings on Migrations" + +### Xaviera Simmons + +“Superunknown (Alive In The),” 2010 +42 C-prints mounted on sintra with brace +20 x 30 in. +Edition of 3 +Courtesy: David Castillo Gallery diff --git a/_posts/2017-07-25-alex-da-corte-book-launch.md b/_posts/2017-07-25-alex-da-corte-book-launch.md new file mode 100644 index 0000000..ac6f39c --- /dev/null +++ b/_posts/2017-07-25-alex-da-corte-book-launch.md @@ -0,0 +1,23 @@ +--- +layout: post +date: '2017-07-25 12:24 -0400' +published: true +title: Alex da Corte Book Launch +event_date: 'Saturday, July 29, 2017, 3-6PM' +categories: left +--- +![alexdacorte.jpg]({{site.baseurl}}/assets/img/alexdacorte.jpg) + +Book launch and barbecue cookout with [Alex Da Corte](http://alexdacorte.com/) celebrating the release of "Slow Graffiti" and "50 Wigs," two recent publications of the artist's work. + +Soak in the summer with food, refreshments, and readings by Alissa Bennett and Sam McKinniss as well as a rotating screening of Da Corte’s latest video work. [RSVP HERE](https://www.facebook.com/events/1423804564368704/?acontext=%7B%22ref%22%3A%2229%22%2C%22ref_notif_type%22%3A%22plan_user_invited%22%2C%22action_history%22%3A%22null%22%7D¬if_t=plan_user_invited¬if_id=1501032207943441) + +Alex Da Corte’s artist’s book "Slow Graffiti," made on the occasion of his show at Vienna Secession, comprises two volumes: a conversation between the artist and the Los Angeles-based writer and critic Bruce Hainley, and Sorcery, a photographic comic strip by New York-based curator and writer Bob Nickas. + +"50 Wigs" includes essays by art writer William Pym, curator Kim Nguyen (CCA Wattis), and artist Sam McKinniss, and is made in collaboration with Da Corte and The Andy Warhol Museum for his 2016 show at Herning Museum of Art. + +[Alex Da Corte](http://alexdacorte.com/) was born in Camden, New Jersey, in 1980. He received a Bachelor of Fine Arts from the University of the Arts, Philadelphia, and a Master of Fine Arts from the Yale University School of Art. His first survey exhibition Free Roses was held at MASS MoCA, North Adams in 2016. Other recent exhibitions include Slow Graffiti at Vienna Secession, Austria (2017); A Man Full Of Trouble at Maccarone Gallery, New York; 50 Wigs at the Herning Museum of Contemporary Art, Herning, Denmark; Dreamlands: Immersive Cinema and Art, 1905–2016 at the Whitney Museum of American Art, New York; A Season in He’ll at Art + Practice, Hammer Museum, Los Angeles (2016); Easternsports at the Institute of Contemporary Art, Philadelphia (2014, together with Jayson Musson). In 2012, Da Corte was awarded a Pew Fellowship in the Arts from the Pew Center for Arts & Heritage. + +Crime enthusiast and writer [Alissa Bennett](http://heinzfellernileisist.bigcartel.com/product/dead-is-better-alissa-bennett) was born in Providence, Rhode Island in 1980. She is the author of DEAD IS BETTER, a twice-yearly zine dedicated to celebrity death, criminal behavior, and the American television program Intervention. Bennett lives and works in Brooklyn. + +[Sam McK­in­niss](http://www.teamgal.com/artists/sam_mc_kinniss) is an artist in New York. His paintings have been fea­tured in numerous group shows and solo presentations internationally. Most recently, his portrait of the pop star Lorde was featured as the cover art for her sophomore album, "Melodrama." As a writer, McKinniss frequently collaborates with Da Corte, having created a monologue featured in the exhibition "Slow Graffiti" as well as contributing a semi-biographical essay to the catalog for "50 Wigs." diff --git a/_posts/2017-08-08-brownbook-64-taxis-issue-release.md b/_posts/2017-08-08-brownbook-64-taxis-issue-release.md new file mode 100644 index 0000000..8db1b46 --- /dev/null +++ b/_posts/2017-08-08-brownbook-64-taxis-issue-release.md @@ -0,0 +1,17 @@ +--- +layout: post +date: '2017-08-08 12:51 -0400' +published: true +title: 'Brownbook 64: Taxis Issue Release' +categories: left +event_date: 'Saturday, August 12, 4–6pm' +tags: + - migrations +--- +![]({{site.baseurl}}/assets/img/unnamed%20(1).jpg) + +Join Ulises for the US release of [Taxis, Issue 64](http://brownbook.tv/magazine) of Brownbook magazine. For this issue, Brownbook takes a road trip with five taxi drivers from across the Middle East and North Africa, joining Ismail Khaouli, one of Morocco's last grand taxi drivers, along the roads that wind through the Atlas Mountains and stopping along Muscat's coastline with Mohamed Al Nuumani, the Omani student who taxis passengers around on the side. [RSVP](https://www.facebook.com/events/1373458529439350/?acontext=%7B%22source%22%3A5%2C%22page_id_source%22%3A1129359703814263%2C%22action_history%22%3A[%7B%22surface%22%3A%22page%22%2C%22mechanism%22%3A%22main_list%22%2C%22extra_data%22%3A%22%7B%5C%22page_id%5C%22%3A1129359703814263%2C%5C%22tour_id%5C%22%3Anull%7D%22%7D]%2C%22has_source%22%3Atrue%7D) + +The issue release party will feature screenings of Brownbook's short video features and interviews, as well as refreshments and an opportunity to browse and purchase a selection of themed back issues. + +Launched over 10 years ago, Brownbook is the essential guide to the contemporary Middle East and North Africa focusing on architecture, travel and other culture. The bimonthly magazine is dedicated to documenting the lesser known stories of the region – from the music of Kuwaiti pearl divers to the Iranian diaspora of Los Angeles. diff --git a/_posts/2017-08-11-marwa-arsanios-screening-and-conversation.md b/_posts/2017-08-11-marwa-arsanios-screening-and-conversation.md new file mode 100644 index 0000000..c94ecca --- /dev/null +++ b/_posts/2017-08-11-marwa-arsanios-screening-and-conversation.md @@ -0,0 +1,25 @@ +--- +layout: post +date: '2017-08-11 10:29 -0400' +published: true +title: Marwa Arsanios Screening and Conversation +categories: left +tags: + - migrations +event_date: 'Saturday, August 19, 2017, 4–6PM' +--- +![marwaarsanios3.jpg]({{site.baseurl}}/assets/img/marwaarsanios3.jpg) + + +Migrations contributor Marwa Arsanios will appear via Skype for a conversation and screening of the artist's two recent video works, “Falling Is Not Collapsing, Falling Is Extending” and "Who is afraid of ideology." + +[RSVP](https://www.facebook.com/events/495482250792905/?acontext=%7B%22source%22%3A5%2C%22page_id_source%22%3A1129359703814263%2C%22action_history%22%3A[%7B%22surface%22%3A%22page%22%2C%22mechanism%22%3A%22main_list%22%2C%22extra_data%22%3A%22%7B%5C%22page_id%5C%22%3A1129359703814263%2C%5C%22tour_id%5C%22%3Anull%7D%22%7D]%2C%22has_source%22%3Atrue%7D) + +- ["Who is afraid of ideology," 2017, Digital video, color,sound 22:20 min](https://walkerart.org/magazine/guerrilla-landscapes-marwa-arsanioss-who-is-afraid-of-ideology-part-i) +- [“Falling Is Not Collapsing, Falling Is Extending,” 2016, Digital video, color, sound 22:34 min.](https://hammer.ucla.edu/exhibitions/2016/hammer-projects-marwa-arsanios/) + +"Through recorded testimony, Who is afraid of ideology? Part I tracks the practical work of the Kurdish autonomous women’s movement—how to use an axe, how to eat fish within its biological cycles of production, when to cut down a tree for survival and when to save it. But the film also explores how individuals come to a conscious participation in the movement—in short, how they become part of the guerrilla." - Mason Leaver-Yap + +In “Falling Is Not Collapsing, Falling Is Extending," Marwa Arsanios addresses the impact of the migration of waste on the changing landscape of Beirut, the city where she lives and works, which has been marked by the rapid development of its urban spaces and burdened by a recent garbage crisis. + +Marwa Arsanios was born in Washington D.C. and lives and works in Beirut, Lebanon. She received her MFA from University of the Arts London in 2007 and was a researcher in the Fine Art department at Jan Van Eyck Academie from 2011 to 2012. She has had solo exhibitions at Witte de With, Rotterdam, the Netherlands (2016); The Hammer, Los Angeles (2016); Kunsthalle Lissabon, Lisbon (2015); and Art in General, New York (2015). Her work was also shown at the 55th Venice Biennale (2013); the 12th Istanbul Biennial (2011); Home Works Forum in Beirut (2010, 2013, 2015); the New Museum, New York (2014); M HKA, Antwerp, Belgium (2013); and nGbK, Berlin (2012). Screenings of her videos have taken place at the Berlinale, Berlin (2010, 2015), e-flux storefront, New York (2009), and Centre Pompidou, Paris (2011). In 2012, Arsanios was awarded the special prize of the Pinchuk Future Generation Art Prize. diff --git a/_posts/2017-08-17-evening-reading.md b/_posts/2017-08-17-evening-reading.md new file mode 100644 index 0000000..34f5e4f --- /dev/null +++ b/_posts/2017-08-17-evening-reading.md @@ -0,0 +1,20 @@ +--- +layout: post +date: '2017-08-17' +published: true +title: Reading Evening +categories: left +tags: + - migrations +event_date: 'Saturday, August 26, 2017, 7PM' +--- +![20988180_1468274746589422_4522942742685998601_o.jpg]({{site.baseurl}}/assets/img/20988180_1468274746589422_4522942742685998601_o.jpg) + + +Book launch for *The Obvious Earth*, an essay collection from Carville Annex Press in San Francisco. Join us for an evening of sounds/sentences with Caren Beilin, Tristan Dahn and Nabil Kashyap. Snacks are likely. Come! + +[Caren Beilin](http://www.noemipress.org/catalog/fiction/beilin/) is the author of the novel *The University of Pennsylvania* (Noemi Press) and a forthcoming book of nonfiction, *SPAIN* (Rescue Press). Her fiction has appeared in *McSweeney’s*, *Fence*, *the Offing* and elsewhere. She lives in Philadelphia. + +[Tristan Dahn](https://tristandahn.bandcamp.com/) is a librarian and semi-frequent performer of music in the Philadelphia arts scene interested in resonance, texture, and form. + +[Nabil Kashyap](http://www.carvilleannexpress.com/shop/the-obvious-earth) wrote *The Obvious Earth* (Carville Annex Press) and has had work appear places like *Actually People Quarterly*, *Colorado Review*, *DIAGRAM*, *Seneca Review* and *Versal*. He is a librarian based in Philadelphia. diff --git a/_posts/2017-08-30-philly-book-launch-of-we-have-the-great-discontent-with-john-shahidi-of-avril50.md b/_posts/2017-08-30-philly-book-launch-of-we-have-the-great-discontent-with-john-shahidi-of-avril50.md new file mode 100644 index 0000000..48fcb94 --- /dev/null +++ b/_posts/2017-08-30-philly-book-launch-of-we-have-the-great-discontent-with-john-shahidi-of-avril50.md @@ -0,0 +1,15 @@ +--- +layout: post +date: '2017-08-30 21:50 -0400' +published: true +title: >- + Philly Book Launch of "We Have the Great Discontent" with John Shahidi of + Avril50 +categories: left +event_date: 'Saturday, September 9 from 4–6 PM' +--- +![WHtGD_small.gif]({{site.baseurl}}/assets/img/WHtGD_small.gif) + +Join us for the Philadelphia launch of We Have the Great Discontent, a book of found poetry by Joel Evey, published by Actual Source. The book’s sole inspiration — the legendary John Shahidi of Avril50 — will be in attendance. There will be snacks, drinks and books for sale. [RSVP](https://www.facebook.com/events/1570751279661659/?acontext=%7B%22action_history%22%3A%22[%7B%5C%22surface%5C%22%3A%5C%22page%5C%22%2C%5C%22mechanism%5C%22%3A%5C%22page_upcoming_events_card%5C%22%2C%5C%22extra_data%5C%22%3A[]%7D]%22%2C%22has_source%22%3Atrue%7D) + +[Joel Evey](http://www.joelevey.com/) is a designer and educator based in Philadelphia, PA. diff --git a/_posts/2017-09-17-ny-art-book-fair.md b/_posts/2017-09-17-ny-art-book-fair.md new file mode 100644 index 0000000..67ae344 --- /dev/null +++ b/_posts/2017-09-17-ny-art-book-fair.md @@ -0,0 +1,17 @@ +--- +layout: post +date: '2017-09-17 22:05 -0400' +published: true +title: NY Art Book Fair +categories: left +--- +![IMG_1744-730x470.jpg]({{site.baseurl}}/assets/img/IMG_1744-730x470.jpg) + +Next weekend Ulises will be at the [New York Art Book Fair](http://nyartbookfair.com/about/), organized by Printed Matter at MoMA PS1. + +- Preview Thursday, September 21, 6-9 pm +- Friday, September 22, 1-7pm +- Saturday, September 23, 11am-9pm +- Sunday, September 24, 11-am-7pm + + diff --git a/_posts/2017-10-08-dear-reader-dignity-has-no-nation-migrant-manifesto.md b/_posts/2017-10-08-dear-reader-dignity-has-no-nation-migrant-manifesto.md new file mode 100644 index 0000000..5b66dcb --- /dev/null +++ b/_posts/2017-10-08-dear-reader-dignity-has-no-nation-migrant-manifesto.md @@ -0,0 +1,25 @@ +--- +layout: post +date: '2017-10-08 18:20 -0400' +published: true +title: 'Dear Reader: Dignity Has No Nationality & Migrant Manifesto' +categories: left +event_date: 'Tuesday, October 10, 6–8PM' +tags: + - migrations +--- +![index.jpeg]({{site.baseurl}}/assets/img/index.jpeg) + +"We are all tied to more than one country. The multilaterally shaped phenomenon of migration cannont be solved unilaterally, or else it generates a vulnerable reality for migrants. Implementing universal rights is essential. The right to be inlcluded belongs to everyone." + +Join Ulises for a group discussion facilitated by Nora Elmarzouky on two timely essays by artist Tania Bruguera: "Dignity Has No Nationality" and "Migrant Manifesto." [RSVP HERE](https://www.facebook.com/events/130839584236830/?acontext=%7B%22ref%22%3A%2229%22%2C%22ref_notif_type%22%3A%22plan_user_invited%22%2C%22action_history%22%3A%22null%22%7D¬if_id=1507492993331242¬if_t=plan_user_invited) + +READINGS: +- [Dignity Has No Nationality](https://drive.google.com/file/d/0B6ClfxGUdTp6YW5NTnplZkZxWGc/view) +- [Migrant Manifesto](https://drive.google.com/open?id=0B6ClfxGUdTp6STNEalJTcXRmVUk) + +Tania Bruguera, born in 1968 in Havana, is a politically motivated performance artist, explores the relationship between art, activism, and social change in works that examine the social effects of political and economic power. By creating proposals and aesthetic models for others to use and adapt, she defines herself as an initiator rather than an author, and often collaborates with multiple institutions as well as many individuals so that the full realization of her artwork occurs when others adopt and perpetuate it. + +Nora Elmarzouky grew up between Egypt and Pennsylvania. With a BA from Tufts University in International Relations, coupled with her studies in Spain, Morocco, and the Czech Republic, her interest in the interactions between humans, culture, identity, and the built environment was enhanced. She is currently supporting alternative Arab spaces, connecting sustainable dots, a Founders Fellow with Impact100, and expanding in.site collaborative in Philadelphia - a collective of designers and researchers working to make urban development and change more participatory and equitable. Additionally, she is managing Friends, Peace, and Sanctuary Project at Swarthmore bringing archives above refugee crises into the contemporary with Syrian and Iraqi refugees and creating art books with artists. + +Image: Tania Bruguera. Immigrant Movement International. First public reading of the Migrant Manifesto. United Nations Students Conference on Human Rights. December 2, 2011. Courtesy IMI. diff --git a/_posts/2017-10-08-xaviera-simmons-superunknown-alive-in-the.md b/_posts/2017-10-08-xaviera-simmons-superunknown-alive-in-the.md new file mode 100644 index 0000000..57cfff6 --- /dev/null +++ b/_posts/2017-10-08-xaviera-simmons-superunknown-alive-in-the.md @@ -0,0 +1,14 @@ +--- +layout: post +date: '2017-10-08 16:54 -0400' +published: true +title: 'Xaviera Simmons, Superunknown (Alive In The)' +categories: left +tags: + - migrations +--- +![]({{site.baseurl}}/assets/img/_MG_0865.jpg) + +Xaviera Simmons, "Superunknown (Alive In The)," 2010. +C-prints mounted on sintra with brace each photo 20 x 30 inches, Edition of 3 +Courtesy: David Castillo Gallery diff --git a/_posts/2017-10-10-book-launch-words-books-and-the-spaces-they-inhabit.md b/_posts/2017-10-10-book-launch-words-books-and-the-spaces-they-inhabit.md new file mode 100644 index 0000000..a0ed22f --- /dev/null +++ b/_posts/2017-10-10-book-launch-words-books-and-the-spaces-they-inhabit.md @@ -0,0 +1,21 @@ +--- +layout: post +date: '2017-10-10 22:57 -0400' +published: true +title: 'Book Launch: Words, Books, and the Spaces They Inhabit' +categories: left +event_date: 'Sunday, October 15, 3–5PM' +--- +![07-NAOC-01.jpg]({{site.baseurl}}/assets/img/07-NAOC-01.jpg) + +Join Ulises for a book launch and conversation celebrating the release of "Words, Books, and the Spaces They Inhabit" (Sternberg Press, 2017) a new publication by Mari Shaw and the first in her series "The Noble Art of Collecting." + +Mari will be joined by Sarah Hamerman, an art librarian working at the Whitney Museum and MoMA Libraries, and scholar Jean-Michel Rabaté, Professor of English Literature, Penn. + +Sarah will present on the legacy of artists' books and artist Ulises Carrion, the namesake of Ulises bookshop who figures prominently in Shaw's book, while Jean-Michel will speak briefly about Walter Benjamin whose ideas on book collecting are an organizing element in Shaw's publication. + +With examples of unexpected collectors and serendipitous outcomes, Shaw investigates the obscure desires that shape art collecting and the public goodwill that results from it. What was lost when the scrolls in the ancient library of Alexandria were destroyed? How did Catherine the Great’s collecting change the way we think? How do Jeff Bezos and Amazon.com expand our appreciation of books as objects? Though the ways we communicate and live vary, history has been created, recorded, and preserved in writing. Words and the spaces that contain them are crucial to an empathetic understanding of our world. + +[RSVP HERE](https://www.facebook.com/events/294418654376928/?active_tab=about) + +[MORE ABOUT THE BOOK](http://www.sternberg-press.com/index.php?pageId=1782) diff --git a/_posts/2017-10-22-programming-and-curatorial-internship.md b/_posts/2017-10-22-programming-and-curatorial-internship.md new file mode 100644 index 0000000..59b96f3 --- /dev/null +++ b/_posts/2017-10-22-programming-and-curatorial-internship.md @@ -0,0 +1,15 @@ +--- +layout: post +date: '2017-10-22 11:51 -0400' +published: false +title: Programming and Curatorial Internship +categories: left +--- +![Internship.jpg]({{site.baseurl}}/assets/img/Internship.jpg) + +Ulises is seeking talented people of all backgrounds to apply for our Programming and Curatorial Internship. If you are a college student or recent grad interested in learning more about arts publishing or arts administration, and its intersection with retail, or are considering a career in the arts, we encourage you to apply. The internship offers training and direct experience working in a growing contemporary arts space and bookstore environment. + +You will take on a variety of development and production based roles working alongside Ulises founders to help plan and document events and programming, conduct research, assist in the implementation of upcoming projects, and maintain shop operations. As an intern you will also gain valuable training, skills, and work experience as well as an opportunity to build a network of professional contacts. An interest in artists’ books, curatorial practice, and community involvement is desirable. We encourage people of all backgrounds to apply—we value diversity of cultures, races and ethnicities, gender expressions, and abilities. Early November 2017 start is preferred. Applicants may apply for one semester (Fall 2017 or Spring 2018) or two (Fall 2017–Spring 2018). + +For a full list of expectations and responsibilities, [click here](https://drive.google.com/open?id=0By5QSqc6j12ObTNFeTBpUzJJVTQ). +To Apply please send a resume and letter of interest to hello@ulises.us with “Internship Application” in the subject line. Applications due by midnight on Sunday, November 12, 2017. diff --git a/_posts/2017-11-25-pablo-helguera-combinatory-lecture.md b/_posts/2017-11-25-pablo-helguera-combinatory-lecture.md new file mode 100644 index 0000000..19c6d93 --- /dev/null +++ b/_posts/2017-11-25-pablo-helguera-combinatory-lecture.md @@ -0,0 +1,17 @@ +--- +layout: post +date: '2017-11-25 09:44 -0500' +published: true +title: 'Pablo Helguera: Combinatory Lecture' +categories: left +tags: + - education +event_date: 'Friday, December 1, 6–8PM' +--- +![PabloHelguera.jpg]({{site.baseurl}}/assets/img/PabloHelguera.jpg) + +Please join Ulises, in partnership with Graduate Studies at Moore College of Art and Design, for a [combinatory lecture](https://www.facebook.com/events/132015904130410/?notif_t=plan_user_associated¬if_id=1511615421012705) with multidisciplinary artist and educator Pablo Helguera organized in conjunction with Ulises’ current quarterly theme "Education." This performance workshop, which incorporates aspects of public speaking and education, consists in the collective writing and presenting of a co-authored lecture. No previous experience of any kind is needed. Different versions of the Combinatory lecture have been presented at the MUAC, Mexico City, Neon Gallery in Bologna Italy, Museo del Hombre in Gran Canaria, and many other locations. + +[Please Register here](https://www.eventbrite.com/e/pablo-helguera-combinatory-lecture-tickets-40716307572?aff=efbeventtix#tickets). Seating is limited. Event is free. + +Pablo Helguera (b. Mexico City, 1971) is a multidisciplinary artist and educator based in New York City. Working in performance, photography, drawing, installation, lectures, and musical composition, among other diverse media, he creates artworks that investigate topics such as history, pedagogy, sociolinguistics, ethnography, memory, and the absurd. Helguera’s projects often blur the line between pedagogy and politically engaged art, raising the question of how educational methodologies can contribute to Social Practice, and vice versa. diff --git a/_posts/2017-12-05-no-4-education.md b/_posts/2017-12-05-no-4-education.md new file mode 100644 index 0000000..b903898 --- /dev/null +++ b/_posts/2017-12-05-no-4-education.md @@ -0,0 +1,66 @@ +--- +title: No. 4 Education +date: 2017-12-05 23:21 -0400 +event_date: December 2017 through February 2018 +layout: post +categories: left +tags: + - education +published: true +--- + + +“Education” considers the ways non-traditional approaches to learning and instruction by artists, researchers, and organizers can effect social transformation. This quarter, Ulises examines the enduring legacies of self-organized and experimental pedagogies. Ulises will probe the broad, urgent challenges to access, power, and value within and outside educational institutions today. While publications are instruments of both self-directed and institutional learning, Ulises celebrates their radical potential to upend knowledge and challenge understandings. + +## Education Programs +- [January 27, 2–3:30PM, "I guess I’m never sure that print is truly linear:" Q&A](https://www.facebook.com/events/191290224948844/?notif_t=plan_user_joined¬if_id=1516472980094867) Launch of David Reinfurt and Robert Wiesenberger's book, "Muriel Cooper," along with a lively discussion between David Reinfert, Mark Owens, and Katie Reilly. +- [January 28, 2–4PM, "Reading Out Loud"](https://www.facebook.com/events/135470050591335/?notif_t=plan_user_joined¬if_id=1516456506312979) Through a series of reading exercises Sepake Angiama will explore the relationship between reading out loud and the body. +- February 3, "[Adjunct Commuter Weekly](https://adjunctcommuterweekly.com/):" Round Table with Dushko Petrovich,founder of ACW, who will discuss life on the art and academic road in a round table with Jennie Shanker, Gregory Laynor, and Daniel Pieczkolon. +- [February 8, 1:30–4:30PM](https://www.facebook.com/events/1591081160970349/), Workshop and Riso Printing with [BFAMFAPhD](http://bfamfaphd.com/) +- [February 10, 2–4PM](https://www.facebook.com/events/1582297128551354/?notif_t=plan_user_joined¬if_id=1517605077830986), Frampton Tolbert, Deputy Director of the [The Center for Urban Pedagogy](http://welcometocup.org/) will present a talk on Design and Civic Engagement. The talk will focus on the history of CUP, its mission and recent projects, along with ongoing initiatives. +- [February 11, 2–4PM](https://www.facebook.com/events/431279823956031/), Book launch and conversation for "[Àsìkò](http://www.asikoartschool.org/): On the Future of Artistic and Curatorial Pedagogies in Africa" with the publication's editorial director Stephanie Baptist and designer Nontsikelelo Mutiti. +- [March 13, 6:30–8PM, Dear Reader: Study in Blue](https://www.facebook.com/events/227155514510749/), a group discussion facilitated by Connie Yu on two essays selected from Sepake Angiama's Reading List. + +## Contributors + +### Pablo Helguera +"Arlington Heights Suite," 2017. Collage on paper, 15 works, 9 x 12 inches. + +“Perhaps the greatest fallacy in theories of human communication is that statements have to have a causal correlation, that our innermost anxieties have a standard verbal equivalent, and that we can only explain a experience through the narration of a logical sequences of events. The overwhelming evidence is that there is no final explanation to any incident, no correlations between them, and that our attempts at understanding any given sequence of events are at best provisional and at worst, hopeless.” —[Pablo Helguera](http://pablohelguera.net/2008/02/the-arlington-heights-suite/), 2008 + +### Caroline Woolard and Susan Jahoda, of BFAMFAPhD +"Ways of Being:" Introduction +Text by [Caroline Woolard](http://carolinewoolard.com/) and [Susan Jahoda](http://www.susanjahoda.com/) of BFAMFAPhD +Design and illustrations by [Emilio Martinez Poppe](http://www.emilio.click/) of BFAMFAPhD + +BFAMFAPhD is a collective of artists, designers, technologists, organizers, and educators who work in the intersection of art, technology, and political economy. Concerned about the impact of debt, rent, and precarity on the lives of creative people, BFAMFAPhD asks: What is a work of art in the age of $120,000 art degrees? BFAMFAPhD creates reports, pedagogical tools, and movement syllabi. Find out more at [BFAMFAPhD.com](http://bfamfaphd.com/). + +### Dushko Petrovich +"Adjunct Commuter Weekly" was the first magazine to address the lifestyle needs and shared interests of a rapidly growing and increasingly influential demographic. Edited and published by [Dushko Petrovich](http://dushkopetrovich.com/)—who for a number of years commuted to teach at Yale, RISD, and Boston University—the inaugural issue of "Adjunct Commuter Weekly" was created entirely by current and former adjunct commuters. It had it all: news, opinion, interviews, features, fashion shoot, photo essays, games, syllabi, poetry, fiction, personal memoirs and advertisements for products of interest to the adjunct commuter. First published on July 30, 2015 the print publication was shuttered on August 10, 2015, due to the financial and time constraints of the adjunct commuting staff, but the original issue, and newer content were rebranded as ACW, which can be found at www.adjunctcommuterweekly.com. + + +### Sepake Angiama +[Sepake Angiama](https://www.artforum.com/search/search=%22Sepake%20Angiama%22) is an educator and curator whose interest revolves around critical, discursive education practices and the “social framework.” Sepake has served as Head of Education for Documenta 14 Kassel, Germany and Athens, Greece; Director of Education for Manifesta 10, Saint Petersburg, Russia; Curator of Public Programmes at Turner Contemporary, Margate, England; and Public Programmes Coordinator at the Hayward Gallery, London. + +Education Reading List +1. Joseph Beuys and Volker Harlan, “What is Art?: Conversations with Joseph Beuys,” +1. Audre Lorde, “Your Silence will not Protect You” +1. Soren Hansen and Jesper Jensen, “The Little Red School Book” +1. Zygmunt Bauman, “On Education” +1. Nancy Dupree, “Ghetto Reality” and “Letter to Young Sisters” +1. Paulo Freire, “Pedagogy of the Oppressed,” “Pedagogy of Hope,” “Education for a Critical +1. Consciousness,” and “Pedagogy of the Heart” +1. Augusto Boal, “Rainbow of Desire” +1. Jacques Ranciere, “Ignorant School Master” +1. Ivan Illich, “Deschooling Society” +1. Silvia Franceschini & Valerio Borgonuovo, “Global Tools 1973-1975: When Education Coincides with Life” +1. Francisco Ferrer, “The Origin and Ideals of the Modern School” +1. Sony Devabhaktuni,‎ Patricia Guaita,‎ Cornelia Tapparelli, “Building Cultures Valparaiso: Pedagogy, practice and poetry at the Valparaiso School of Architecture and Design +1. John Dewey, “Art as Experience” +1. Radical Education Forum, “Radical Education Workbook” +1. Bell Hooks, “Teaching to Transgress” and “Teaching Community: A pedagogy of hope” +1. Grant Kester, “Conversation Pieces: Community and Communication in Modern Art” +1. Heidi Zafia Mirza, “Race, Gender and Educational Desire: Why black women succeed and fail” +1. Linda Tuhiwai Smith, “Decolonizing Methodologies: Research and Indigenous Peoples” +1. Sara N. Davis, Mary Crawford, and Jadwiga Sebrechts, (Editors), “Coming Into Her Own: Educational Success in Girls and Women” +1. Maurice Stein and‎ Larry Miller, “Blueprint for Counter Education” diff --git a/_posts/2018-01-05-education-launch-back-to-school-sale.md b/_posts/2018-01-05-education-launch-back-to-school-sale.md new file mode 100644 index 0000000..433dd82 --- /dev/null +++ b/_posts/2018-01-05-education-launch-back-to-school-sale.md @@ -0,0 +1,16 @@ +--- +layout: post +date: '2018-01-05 11:02 -0500' +published: true +title: Education Launch Party & Back–to–School Sale +event_date: 'Friday, January 12, 2018, 6:30–9:30PM' +categories: left +tags: + - Education +--- +![26168859_1588964994520396_4701916880002131669_n.jpg]({{site.baseurl}}/assets/img/26168859_1588964994520396_4701916880002131669_n.jpg) + + +Join us in celebrating our fourth quarterly season, Education, with a party and back-to-school sale! The festivities begin at 6:30pm. Warm libations and PB&Js will be provided along with a special DJ set by Rana Ransom. [RSVP](https://www.facebook.com/events/822636027916827/?notif_t=plan_user_joined¬if_id=1515171156219782) + +Sale Sale Sale: 15% off select items all weekend long! diff --git a/_posts/2018-01-20--i-guess-i-m-never-sure-that-print-is-truly-linear.md b/_posts/2018-01-20--i-guess-i-m-never-sure-that-print-is-truly-linear.md new file mode 100644 index 0000000..7bf5f6d --- /dev/null +++ b/_posts/2018-01-20--i-guess-i-m-never-sure-that-print-is-truly-linear.md @@ -0,0 +1,23 @@ +--- +layout: post +date: '2018-01-20 12:56 -0500' +published: true +title: '"I guess I’m never sure that print is truly linear."' +categories: left +event_date: 'Saturday, January 27, 2–3:30PM' +tags: + - education +--- +![26805024_1601924936557735_4792805289535588420_n.jpg]({{site.baseurl}}/assets/img/26805024_1601924936557735_4792805289535588420_n.jpg) + +Join us for the launch of "Muriel Cooper" by David Reinfurt and Robert Wiesenberger along with a lively discussion between author David Reinfert, designer Mark Owens, and Katie Reilly, William T. Ranney Director of Publishing at Philadelphia Museum of Art. [RSVP](https://www.facebook.com/events/191290224948844/?notif_t=plan_user_joined¬if_id=1516459366897379) + +"I guess I’m never sure that print is truly linear." —Muriel Cooper + +Muriel Cooper (1925–1994) was the pioneering designer who created the iconic MIT Press colophon (or logo)—seven bars that represent the lowercase letters “mitp” as abstracted books on a shelf. She designed a modernist monument, the encyclopedic volume The Bauhaus (1969), and the graphically dazzling and controversial first edition of Learning from Las Vegas (1972). She used an offset press as an artistic tool, worked with a large-format Polaroid camera, and had an early vision of e-books. More than two decades after her career came to a premature end, Muriel Cooper’s legacy is still unfolding. + +[Mark Owens](http://www.lifeofthemind.net/) is a designer, writer, and curator working between New York, Los Angeles, and Philadelphia. He holds an MFA in graphic design from Yale University and an MA in English and literary theory from Duke University. For the past decade he has worked as an independent graphic designer, primarily for publishers and clients in the cultural realm. He is co-editor with Zak Kyes of the catalogue for the exhibition Forms of Inquiry at the Architectural Association, London, and his essays have appeared in Dot Dot Dot, Visible Language, Grafik, PIN-UP, Bricks from the Kiln, and Experimental Jetset’s recent monograph, Statement and Counter-Statement. + +[David Reinfurt](http://arts.princeton.edu/people/profiles/reinfurt/) is 1/2 of [Dexter Sinister](http://www.dextersinister.org/), 1/4 of [The Serving Library](http://www.servinglibrary.org/), and 1/1 of [O-R-G inc](http://www.o-r-g.com/). Dexter Sinister started as a small workshop on the lower east side of Manhattan and has since branched pragmatically into projects with and for contemporary art institutions. The Serving Library publishes a semi-annual journal, maintains a physical collection, and circulates PDF texts through its website. O-R-G is a small software company. David currently teaches at Princeton University and his work is included in the permanent collections of Cooper Hewitt National Design Museum, Museum of Modern Art, Walker Art Center, and the Whitney Museum of American Art. David is the 2016-2017 Mark Hampton Rome Prize fellow. + +Katie Riley is the current William T. Ranney Director of Publishing at Philadelphia Museum. Before coming to Philadelphia she held positions as Director of Publications at the Carnegie Museum in Pittsburg, and Editor of Scholarly Publications at the Art Institue of Chicago. diff --git a/_posts/2018-01-20-reading-out-loud.md b/_posts/2018-01-20-reading-out-loud.md new file mode 100644 index 0000000..e062520 --- /dev/null +++ b/_posts/2018-01-20-reading-out-loud.md @@ -0,0 +1,18 @@ +--- +layout: post +date: '2018-01-20 12:50 -0500' +published: true +title: Reading Out Loud +categories: left +event_date: 'Sunday, January 28, 2–4PM' +tags: + - education +--- +![26840783_1602674933149402_8425449545268900409_o.jpg]({{site.baseurl}}/assets/img/26840783_1602674933149402_8425449545268900409_o.jpg) + + +How do we read? Why do we read? With whom? When and where? + +What happens to our bodies when we read out loud? Who do we become and how does reading collectively transform the act of reading to oneself? Through a series of reading exercises Sepake Angiama will explore the relationship between reading out loud and the body. [RSVP](https://www.facebook.com/events/135470050591335/?notif_t=plan_user_joined¬if_id=1516456506312979) + +Sepake Angiama is an educator and curator whose interest revolves around critical, discursive education practices and the “social framework.” Most recently she was the Head of Education for Documenta 14 Kassel, Germany and Athens, Greece where she co-initiated with ifa 'Under the Mango Tree; sites of learning' bringing together at artist-led schools, libraries and initiatives with a focus on radical education practices, indigenous practices and the global South. Currently she is a bak (basis voor actual kunst) fellow where her research 'Her Imaginary' addresses intersectional feminism, brutalist architecture and science fiction. Sepake joins us amidst 'All Good Things Must Begin: A conversation between Audre Lorde and Octavia Butler' her research residency at SBC Gallerie in Montréal. diff --git a/_posts/2018-02-01-adjunct-commuter-weekly-round-table-with-dushko-petrovich.md b/_posts/2018-02-01-adjunct-commuter-weekly-round-table-with-dushko-petrovich.md new file mode 100644 index 0000000..9ccdf12 --- /dev/null +++ b/_posts/2018-02-01-adjunct-commuter-weekly-round-table-with-dushko-petrovich.md @@ -0,0 +1,22 @@ +--- +layout: post +date: '2018-02-01 23:37 -0500' +published: true +title: 'Adjunct Commuter Weekly: Round Table with Dushko Petrovich' +event_date: 'Saturday, February 3, 2–4PM' +tags: + - education +categories: left +--- +![Adjunct.jpg]({{site.baseurl}}/assets/img/Adjunct.jpg) + + +Educator, artist, and publisher of [Adjunct Commuter Weekly](https://adjunctcommuterweekly.com/), Dushko Petrovich, will discuss life on the art and academic road in a round table with Jennie Shanker, Gregory Laynor, and Daniel Pieczkolon. [RSVP](https://www.facebook.com/events/181343182466723/) + +Adjunct Commuter Weekly was the first magazine to address the lifestyle needs and shared interests of a rapidly growing and increasingly influential demographic. Edited and published by Dushko Petrovich—who for a number of years commuted to teach at Yale, RISD, and Boston University—the inaugural issue of Adjunct Commuter Weekly was created entirely by current and former adjunct commuters. It had it all: news, opinion, interviews, features, fashion shoot, photo essays, games, syllabi, poetry, fiction, personal memoirs and advertisements for products of interest to the adjunct commuter. First published on July 30, 2015 the print publication was shuttered on August 10, 2015, due to the financial and time constraints of the adjunct commuting staff, but the original issue, and newer content were rebranded as ACW, which can be found at [www.adjunctcommuterweekly.com](www.adjunctcommuterweekly.com). + +Jennie Shanker is an artist and adjunct activist, initially working with the United Academics of Philadelphia on its city-wide organizing, and is currently serving as the VP of TAUP, the union at Temple University for FT and PT faculty, librarians and academic professionals. + +Gregory Laynor, poet and scholar of media and performance, works as a medical librarian and humanities adjunct at Temple University. + +Daniel Pieczkolon is an adjunct, poet, and activist. He currently teaches Writing courses at Arcadia University & Literature courses at Rowan University and works as an organizer for the United Academics of Philadelphia. diff --git a/_posts/2018-02-04-presentation-the-center-for-urban-pedagogy.md b/_posts/2018-02-04-presentation-the-center-for-urban-pedagogy.md new file mode 100644 index 0000000..89816d6 --- /dev/null +++ b/_posts/2018-02-04-presentation-the-center-for-urban-pedagogy.md @@ -0,0 +1,15 @@ +--- +layout: post +date: '2018-02-05 17:00 -0500' +published: true +title: 'Presentation: The Center for Urban Pedagogy' +categories: left +event_date: 'Saturday, February 10, 2–4PM' +tags: + - education +--- +![VendorPower4.jpg]({{site.baseurl}}/assets/img/VendorPower4.jpg) + +Frampton Tolbert, Deputy Director of the [Center for Urban Pedagogy](http://welcometocup.org/) will present a talk on Design and Civic Engagement at Ulises. The talk will focus on the history of CUP, its mission and recent projects, along with ongoing initiatives. + +The Center for Urban Pedagogy (CUP) is a nonprofit organization that uses the power of design and art to increase meaningful civic engagement. CUP collaborates with designers, educators, advocates, students, and communities to make educational tools that demystify complex policy and planning issues. diff --git a/_posts/2018-02-04-ways-of-being-support.md b/_posts/2018-02-04-ways-of-being-support.md new file mode 100644 index 0000000..d890fb3 --- /dev/null +++ b/_posts/2018-02-04-ways-of-being-support.md @@ -0,0 +1,25 @@ +--- +layout: post +date: '2018-02-04 17:11 -0500' +published: true +title: POSTPONED DUE TO EAGLES VICTORY PARADE! Ways of Being with BFAMFAPhD +categories: left +event_date: 'Thursday, February 8' +tags: + - education +--- +![PastedGraphic-1.png]({{site.baseurl}}/assets/img/PastedGraphic-1.png) + +Support Workshop: 1:30-4:00pm at the ICA + +Risograph Workshop: 4:30-6:00pm at the ICA + +[Please RSVP](https://www.facebook.com/events/1591081160970349/) + +How can we support ourselves and each other? This workshop looks at the ways in which we meet our needs for wellbeing in order to dream, practice, and work on any project. Support extends beyond the life of our projects, often shaping the ways in which we navigate the contradictions of living and working on independent projects. Join us for an attunement, discussion, and mutual connection from 1:30-4:00pm and for a Risograph workshop feature an excerpt from our forthcoming book from 4:30-6:00pm. + +This workshop will be led by [BFAMFAPhD](http://bfamfaphd.com) collective members [Susan Jahoda](http://www.susanjahoda.com/), [Emilio Martinez Poppe](http://www.emilio.click/), and [Caroline Woolard](http://carolinewoolard.com/). The workshop comes from the collective BFAMFAPhD's pedagogical project, "Ways of Being." We invite people from all backgrounds and identities to participate in our programming. This is a LGBTQIA friendly space. + +"Ways of Being" is a multi-platform pedagogical project which offers practices of collaboration, contemplation, and social-ecological analysis to postsecondary visual artists, arts students, and arts educators. Ways of Being is for educators who wish to connect art to economy; for students who make artworks that reflect the conditions of their own production. Ways of Being is a book, a deck of cards, and a cutting-edge, interactive educational website. The interactive website with videos games will be finished by September 2018 and the book be in print by January of 2019. The publisher is Punctum Books. + +[BFAMFAPhD](/) is a collective of artists, designers, technologists, organizers, and educators who work in the intersection of art, technology, and political economy. Concerned about the impact of debt, rent, and precarity on the lives of creative people, BFAMFAPhD asks: What is a work of art in the age of $120,000 art degrees? Susan Jahoda is a Professor in Studio Arts at the University of Amherst, MA; Emilio Martinez Poppe is the Program Manager at Fourth Arts Block (FABnyc), New York, NY; Caroline Woolard is an Assistant Professor of Sculpture at The University of Hartford, CT. Core members not represented in this CV include Vicky Virgin, a Research Associate at The Center for Economic Opportunity, New York, NY and Agnes Szanyi, a lecturer and PhD candidate in Sociology at The New School, New York, NY. diff --git a/_posts/2018-03-10--s-k-book-launch.md b/_posts/2018-03-10--s-k-book-launch.md new file mode 100644 index 0000000..dff4ea4 --- /dev/null +++ b/_posts/2018-03-10--s-k-book-launch.md @@ -0,0 +1,24 @@ +--- +layout: post +date: '2018-03-10 12:14 -0500' +published: true +title: Àsìkò Book Launch +categories: left +event_date: 'Sunday, February 11, 2–4PM' +tags: + - education +--- +![]({{site.baseurl}}/assets/img/27500209_10155333277445872_8427404642788443_o%20(1).jpg) + +Join Ulises for a book launch and conversation for "Àsìkò: On the Future of Artistic and Curatorial Pedagogies in Africa" with the publication's editorial director Stephanie Baptist and designer Nontsikelelo Mutiti. + +[Àsìkò](http://www.asikoartschool.org/) is an innovative program started in 2010, by the Centre for Contemporary Art, Lagos, Nigeria to redress the frequently outdated or non-existent artistic and curatorial curricula at tertiary institutions across Africa. + +Each year a cohort of approximately 12-15 emerging African artists and curators join an international faculty of practicing artists, art historians, curators and writers, for an intensive thirty-five-day course of study in art and curatorial history, methodologies, and professional development. Moving between models of laboratory, residency, and academy, Àsìkò privileges experimentation over conventional approaches to art making and curatorial inquiry, encouraging participants to workshop ideas, proposals and projects for long-term development and implementation. + +"Àsìkò: On the Future of Artistic and Curatorial Pedagogies in Africa" chronicles six editions of the program: the first two editions having taken place in Lagos, Nigeria and the subsequent four editions in Accra, Dakar, Maputo, and Addis Ababa, the capitals of Ghana, Senegal, Mozambique and Ethiopia, respectively. The publication documents each unique but related iteration and indexes the work and reflections of the more than 70 cultural producers (from 15 African countries) who have participated in Àsìkò from 2010-2016. + +[Stephanie Baptist](https://stephaniebaptist.carbonmade.com/) is an independent cultural producer, editor and writer. For over a decade she has collaborated with noted contemporary artists, organizations and individuals. She has previously served as Program Director for En Foco, a non profit photography organization and as Head of Exhibitions and Public Programs for Tiwani Contemporary an art gallery in London. Stephanie has edited a number of gallery monographs for: Rotimi-Fani Kayode, Simone Leigh, Njideka Akunyili, Mary Evans, and Barbara Walker. She has also been contributing editor for Another Africa and a writer for Contemporary And, both online platforms dedicated to contemporary art from Africa. She has an MA in Arts Administration and Cultural Policy from Goldsmiths University of London. Stephanie is the Curator and Director of Medium Tings, an apartment gallery and project space in Crown Heights, Brooklyn. + +[Nontsikelelo Mutiti](http://nontsikelelomutiti.com/) is a Zimbabwean-born interdisciplinary artist and educator. Mutiti holds a diploma in multimedia art from the Zimbabwe Institute of Vigital Arts, and an MFA from the Yale School of Art, with a concentration in graphic design. Recently, she has been a resident artist at the Museum of Contemporary Art Detroit, Recess, and the Centre for Book Arts, both in New York City. In 2015, Mutiti was awarded the Joan Mitchell Foundation Emerging Artist Grant in its inaugural year. Mutiti has participated in several group shows including "Salon Style" at the Studio Museum, a special screening for "Dreamlands" at the Whitney Museum, "Talking Pictures" at the Metropolitan Museum, and "THREE: On Visibility and Camouflage" at We Buy Gold. Mutiti produces project-based works, founding Black Chalk and Co with Tinashe Mushakavanhu, a collective of writers, artists, curators, and educators that initiate research-based projects that result in publications, archival projects, and events. As a collaborative team, Black Chalk and Co completed a residency at Keleketla Library in Johannesburg. Mutiti is currently Assistant Professor in Graphic Design at Virginia Commonwealth University. + diff --git a/_posts/2018-03-10-dear-reader-study-in-blue.md b/_posts/2018-03-10-dear-reader-study-in-blue.md new file mode 100644 index 0000000..4765bb8 --- /dev/null +++ b/_posts/2018-03-10-dear-reader-study-in-blue.md @@ -0,0 +1,20 @@ +--- +layout: post +date: '2018-03-10 13:10 -0500' +published: true +title: 'Dear Reader: Study in Blue' +event_date: 'Tuesday, March 13, 6:30–8PM' +categories: left +tags: + - education +--- +![dear-reader.jpg]({{site.baseurl}}/assets/img/dear-reader.jpg) + +Join Ulises for a group discussion facilitated by Connie Yu on the essays “Commitment as a Non-Performative" by Sara Ahmed, Andrea Long Chu's rumination in the work "Study in Blue: affect, trauma, event" from Women & Performance, 2017, and excerpts from the book “The Undercommons" by Fred Moten and Stefano Harney.. [RSVP](https://www.facebook.com/events/227155514510749/) The readings are available through the links below. + +- [Chu, Andrea Long. "Study in Blue: trauma, affect, event." _Women and Performance_, 27.3, 2017.](https://www.womenandperformance.org/bonus-articles-1/andrea-long-chu-27-3) +- [Moten, Fred, and Stefano Harvey. "The University and the Undercommons." _The Undercommons: Fugitive Planning & Black Study_, 2013.](https://drive.google.com/file/d/1g9Rkz28SuuhZPpHPQ2A9aquY0iKEOo5b/view?usp=sharing) + +Connie will explore the aporia of learning and teaching in and around institution toward what Sara Ahmed calls a “process of estrangement,” when what is strange about a given, taken, is relieved. Is it a real inertia in publicizing feeling (Chu) or professionalizing labor (Moten & Harney)? + +Connie Yu is a writer living in Philadelphia, moving toward performance and attending to queer domestic labor, representations of the AsAm diaspora, alternate and constricted transmissions of information, the body and what it wears, and how to work from here. They are the Brodsky Gallery Coordinator at the Kelly Writers House, and a teaching artist at Center for Creative Works. diff --git a/_posts/2018-03-10-pasp.md b/_posts/2018-03-10-pasp.md new file mode 100644 index 0000000..e2cfd9b --- /dev/null +++ b/_posts/2018-03-10-pasp.md @@ -0,0 +1,51 @@ +--- +layout: post +title: 'Publishing as Practice: A Three Part Publishing Residency' +published: true +tags: + - pasp +date: '2018-03-10' +--- + +Ulises presents Publishing As Practice, a three-part publisher residency designed to explore publishing as an incubator for new forms of editorial, curatorial, and artistic practice. Three experimental art publishers will activate Ulises as an exhibition space and public programming hub, engaging the public through workshops, discussions, and projects. + +Residents include Hardworking Goodlooking, the publishing arm of Philippines-based, social practice platform The Office of Culture and Design; Dominica, an imprint run by Martine Syms dedicated to exploring blackness as a topic, reference, marker and audience in visual culture; and Bidoun, a non-profit organization focused on art and culture from the Middle East and its diasporas. These practitioners reveal that publishing is an activity in constant flux, one that continues to evolve and grow in the era of drag and drop, copy and paste. The project will culminate in a publication featuring the work of all three residents. + +### [Hardworking Goodlooking](http://officeocd.com/)
April 7–31, 2018 +**Archive: [kulambobulleting](https://kulambobulleting.tumblr.com/) + + +**April 14–15, 1:30–2:30PM**
+LISTENING TO THE TINY
+Deep listening exercises
+{: .no-indent } + +**April 18-20, 1:30-3:30PM**
+ATE, KUYA, TITA
+Open studio visiting hours with Ate Clara Balaguer, Kuya Kristian Henson, and Tita Dante Carlos +{: .no-indent } + +**April 22, 6PM until late**
+MOSQUITO PARTY & CLOSING
+Deep listening lecture performance
+Mosquito press launch
+Open to the public
+{: .no-indent } + +### [Martine Syms/Dominica](http://dominicapublishing.com/)
July 22–November 4, 2018 +**July 22, 2–6PM**
+Residency Kickoff: Dominica & Friends Reading

+{: .no-indent } + +### [Bidoun](https://bidoun.org/)
November 29, 2018–January 2019 +**November 29, 7–8:45PM**
+REZA ABDOH: THEATRE VISIONARY
+Screening at Lightbox Film Center
+Free & open to the public
+[Reserve tickets](https://lightboxfilmcenter.org/programs/reza-abdoh-theatre-visionary?fbclid=IwAR0xeKPyG0W6CLQXCBP-RkqZJErNSmJWZq7xG5kzii6w_pUn0ZsF_S2_2Qs) +{: .no-indent } + +Support for this project has been provided to Kayla Romberger by [The Pew Center for Arts & Heritage](https://www.pcah.us/). +{: .left-justify } + +[![Pew Logo]({{site.baseurl}}/assets/img/pc_mag_RGB.svg)](://www.pcah.us/) diff --git a/_posts/2018-03-12-hwgl.md b/_posts/2018-03-12-hwgl.md new file mode 100644 index 0000000..1b1bf7f --- /dev/null +++ b/_posts/2018-03-12-hwgl.md @@ -0,0 +1,24 @@ +--- +title: Hardworking Goodlooking +date: 2018-03-12 +event_date: April 7–31, 2018 +layout: post +categories: left +tags: + - hwgl +published: true +--- +![]({{site.baseurl}}/assets/img/Hardworking%20Goodlooking_Mosquito_press-82%20(5).jpg) + +[Hardworking Goodlooking (HWGL)](http://officeocd.com/) was established in 2013 by The Office of Culture and Design (The OCD) as a publishing imprint and graphic design studio interested in decolonization of aesthetic voices, vernacular artisanry, and giving value to the invisible. Founded by Clara Lobregat Balaguer and Kristian Henson in 2010, the OCD is a research and project production platform out of Parañaque City and Brooklyn, for social practice in art and design. + +![HardWorkingGoodLooking.gif]({{site.baseurl}}/assets/img/HardWorkingGoodLooking.gif) + +Hardworking Goodlooking's three-week residency will be an exercise in running a “mosquito press,” referring to the illegal presses of the Martial Law era (1972-1986) that were critical of the conjugal dictatorship of Ferdinand and Imelda Marcos. As freedom of the press is currently threatened under the regime of neoauthoritarian president Rodrigo Duterte, HWGL will organize a series of intimate talks (and potluck meals) to discuss the Philippines’ current political situation with Filipino academics. The content generated in these discussions—plus content mined from long-running research into ideological internet trolls—will be printed as an homage to the mosquito press format: compiled as the documentation/ephemera of collective radical action, quickly and precariously printed, critical of a dictatorial regime, distributed via informal networks, often at personal risk. + +_They Can Never Kill All of the Mosquitoes +Reviving the Mosquito Press_ + +- April 14-15, Deep Listening Forum + Potluck Discussions +- April 18-20, Open Studio Visiting Hours +- April 22, Deep Listening Lecture Performance + Mosquito Press Launch diff --git a/_posts/2018-05-30-in-too-deep.md b/_posts/2018-05-30-in-too-deep.md new file mode 100644 index 0000000..fdfa629 --- /dev/null +++ b/_posts/2018-05-30-in-too-deep.md @@ -0,0 +1,13 @@ +--- +layout: post +date: '2018-05-30 18:43 -0400' +published: true +title: 'IN TOO DEEP "Walking & Talking" ' +categories: left +event_date: 'Thursday, May 31, 7:30–10PM' +--- +![cyqtjcDkxawx.jpg]({{site.baseurl}}/assets/img/cyqtjcDkxawx.jpg) + +A Movie Evening with YOWIE and mustarrrrd at Ulises! [RSVP](https://www.facebook.com/events/106847163534723/) + +Join us for our first co-curated movie night! The theme is IN TOO DEEP and we'll be showing "Walking and Talking" starring Catherine Keener, Anne Heche and Liev Schreiber. Free snacks and drinks while supplies last! diff --git a/_posts/2018-07-16-martine-syms-dominica-residency-kickoff.md b/_posts/2018-07-16-martine-syms-dominica-residency-kickoff.md new file mode 100644 index 0000000..eb6f15b --- /dev/null +++ b/_posts/2018-07-16-martine-syms-dominica-residency-kickoff.md @@ -0,0 +1,18 @@ +--- +layout: post +date: '2018-07-16 20:59 -0400' +published: true +title: Martine Syms/Dominica Residency Kickoff +categories: left +event_date: 'Sunday, July 22, 2–6pm' +--- +![]({{site.baseurl}}/assets/img/11_SYMS_Notes-On-Gesture%20183.jpg) +Martine Syms, still from "Notes on Gesture," 2015 + +Join us on Sunday, July 22 from 2 until 6 pm to celebrate the kickoff of Dominica’s residency with readings by [Diamond Stingily](https://i-d.vice.com/en_uk/article/gyw7nb/the-world-needs-more-artists-like-diamond-stingily), [Rami George](http://ramigeorge.net/), [Rocket Caleshu](http://bwr.ua.edu/2016-contest-an-interview-with-nonfiction-winner-rocket-caleshu/), and [Carolyn Lazard](http://www.carolynlazard.com/), followed by a DJ set with Yassir "Yaya V" Valentine. Drinks, snacks, and summer vibes. + +Publishing as Practice is a three-part publishing residency, designed to explore publishing as an incubator for new forms of editorial, curatorial, and artistic practice. + +For the second installment of Publishing as Practice: Dominica—the publishing imprint founded by Martine Syms in 2011 dedicated to exploring blackness as a reference, marker, and topic—will transform the Ulises space into a shop selling new screen printed apparel and feature select texts, visual materials, and programming produced by the artist and collaborators. Syms will refashion the Dominica and Ulises websites into in a digital storefront and live streaming platform in the style of an online Home Shopping Network. Publishing as Practice: Martine Syms considers the shop as a central aspect of independent publishing—not only a site of a commercial transaction but also a locus of social exchange. + +Support for Publishing As Practice has been provided to Kayla Romberger by The Pew Center for Arts & Heritage. diff --git a/_posts/2018-07-16-martine-syms-dominica.md b/_posts/2018-07-16-martine-syms-dominica.md new file mode 100644 index 0000000..95debe2 --- /dev/null +++ b/_posts/2018-07-16-martine-syms-dominica.md @@ -0,0 +1,18 @@ +--- +title: Martine Syms/Dominica +date: 2018-07-16 21:13 -0400 +layout: post +categories: left +published: true +--- +July 22–November 4, 2018 + +![2018_Martine_Syms_Dominica_Ulises_W-6.jpg]({{site.baseurl}}/assets/img/2018_Martine_Syms_Dominica_Ulises_W-6.jpg) + +Photo: [Constance Mensh](http://www.constancemensh.com/) + +For the second installment of Publishing As Practice, [Martine Syms](http://martinesy.ms/) will front as [Dominica](http://dominicapublishing.com/), the publishing imprint founded by the artist in 2011 dedicated to exploring blackness as a reference, marker, and topic. For the duration of the residency, Martine will transform the Ulises space into a shop selling new screen printed apparel and feature select texts, visual materials, and programming produced by the artist and collaborators. Syms will refashion the Dominica and Ulises websites into in a digital storefront and live streaming platform in the style of an online Home Shopping Network. Publishing as Practice: Martine Syms considers the shop as a central aspect of independent publishing—not only a site of commercial transaction, but also a locus of social exchange. + +[Martine Syms](http://martinesy.ms/) is an artist and conceptual entrepreneur based in Los Angeles. Syms works across publishing, video, and performance to examine representations of blackness. Her artwork has been exhibited and screened extensively, including presentations at the Museum of Modern Art, Hammer Museum, ICA London, New Museum, Museum of Contemporary Art Los Angeles, and The Studio Museum in Harlem, among other institutions. From 2007-2011 she was the co-director of the Chicago artist run project space Golden Age, and she currently runs Dominica Publishing, an imprint dedicated to exploring blackness in visual culture. She is a faculty member in the School of Art at the California Institute of the Arts. + +- Sunday, July 22, 2–6pm Dominica & Friends Readings & Residency Kickoff diff --git a/_posts/2018-07-25-after-ulises-carri-n.md b/_posts/2018-07-25-after-ulises-carri-n.md new file mode 100644 index 0000000..fda19f7 --- /dev/null +++ b/_posts/2018-07-25-after-ulises-carri-n.md @@ -0,0 +1,17 @@ +--- +layout: post +date: '2018-07-25 10:06 -0400' +published: true +title: After Ulises (Carrión) +categories: left +event_date: 'Sunday, July 29, 2018, 2–4PM' +--- +![37661338_1809499885800238_3356474872619335680_o.jpg]({{site.baseurl}}/assets/img/37661338_1809499885800238_3356474872619335680_o.jpg) + +Please join us for a very special presentation entitled "After Ulises (Carrión): Artists' Books and DIY Publishing in & Around The Netherlands." [RSVP](https://www.facebook.com/events/442920809507833/) + +As a project space for bookworks, Ulises Carrión's "Other Books and So" (Amsterdam, 1975-79) was an experiment across contemporary art, poetry and experimental archiving. It continued a history that began with Fluxus in the 1960s and became the blueprint for a number of artists' books and DIY publishing spaces, initiatives and projects in and around the Netherlands, from the 1980s until today. In his informal talk, Florian Cramer will reconstruct this history - and its contemporary overlaps with zine culture and media activism, - show excerpts of Ulises Carrión's video works and, with a bit of luck, phone in a former collaborator of Carrión in the Netherlands. + +[Florian Cramer](https://www.phdarts.eu/Supervisors/FlorianCramer) is a reader at Willem de Kooning Academy, Rotterdam, Netherlands, where he also volunteers for the DIY publishing and experimental arts venues & projects PrintRoom, De Player and ZineCamp. He wrote the afterword for Alessandro Ludovico's "Post-Digital Print" and co-authored the zine "The Moral of the Xerox: Missalette" with former Ulises resident Clara Balaguer. + +Image: Thunderclap, zine by Amy Suo Wu, that distributes the erased writings of Chinese anarcho-feminist, He-Yin Zhen (1886-1920) diff --git a/_posts/2018-10-16-bio-artists-canceled-texts-and-the-world-wide-web.md b/_posts/2018-10-16-bio-artists-canceled-texts-and-the-world-wide-web.md new file mode 100644 index 0000000..f8b7ea1 --- /dev/null +++ b/_posts/2018-10-16-bio-artists-canceled-texts-and-the-world-wide-web.md @@ -0,0 +1,20 @@ +--- +layout: post +date: '2018-10-16 22:32 -0400' +published: true +title: 'Bio: Artists’ Canceled Texts and the World Wide Web' +categories: left +event_date: 'Saturday, October 27, 6pm' +--- +![Bio_Cover-2.gif]({{site.baseurl}}/assets/img/Bio_Cover-2.gif) + +Bio: Artists’ Canceled Texts and the World Wide Web, +Maryam Monalisa Gharavi in Conversation with Malcolm Harris + +Maryam Monalisa Gharavi’s "[Bio](http://www.inventorypress.com/product/bio)" (Inventory Press, 2018) is a hybrid work that reconfigures canceled text and the World Wide Web. The book captures a span of 365 days during which the artist updated the 160-character “bio” section of her Twitter account each day. While tweets are regularly captured by corporate data storage centers this “bio” section remains the only untraceable and non-archived part of the software’s superstructure. “Bio” ultimately left no record of itself, complicating the normative binaries of online/offline and digital/print. An experiment in erasure, self-deletion, and visibility in the expanded sphere of the net, “Bio” anchors itself in the wider lineage of artists’ canceled texts, but in the age of new data as “soft” power. + +The work featured in the New Museum Triennial anthology, The Animated Reader: Poetry of “Surround Audience” (ed. Brian Droitcour), and is currently on view as a 365-day internet installation at [Contemporary Journal](https://thecontemporaryjournal.org/issues/bio) (ed. Carolina Rito). + +Maryam Monalisa Gharavi is an artist, poet, and theorist whose work explores the interplay between aesthetic and political valences in the public domain. Prior publications include a translation of Waly Salomão’s Algaravias: Echo Chamber (Ugly Duckling Presse), nominated for a 2017 PEN Award for Poetry in Translation; the poetry volume The Distancing Effect (BlazeVOX); the artist publication Apparent Horizon 2 (Bonington Gallery); and the chapbook Alphabet of an Unknown City (Belladonna*). + +[Malcolm Harris](https://twitter.com/BigMeanInternet) is a writer in Philadelphia and the author of "Kids These Days: Human Capital and the Making of Millennials." \ No newline at end of file diff --git a/_posts/2018-11-01-dominica-closing-with-amanda-harris-williams-dj-osagie.md b/_posts/2018-11-01-dominica-closing-with-amanda-harris-williams-dj-osagie.md new file mode 100644 index 0000000..a49c39a --- /dev/null +++ b/_posts/2018-11-01-dominica-closing-with-amanda-harris-williams-dj-osagie.md @@ -0,0 +1,19 @@ +--- +layout: post +date: '2018-11-01 22:34 -0400' +published: true +title: Dominica Closing with Mandy Harris Williams + DJ Osagie +event_date: 'Sunday, November 4, 2–6 pm' +categories: left +--- +![IMG_6688.JPG]({{site.baseurl}}/assets/img/IMG_6688.JPG) + +Celebrate the closing of our second of three publisher residents for Publishing as Practice: [Martine Syms](http://martinesy.ms/) has operated through [Dominica Publishing](http://dominicapublishing.com/). The event will launch with a workshop with LA/NOLA/NYC-based artist [Mandy Harris Williams](https://www.instagram.com/idealblackfemale) and continue with a set from beloved local DJ, [Osagie OG](https://soundcloud.com/osagiebeats). Discussion, beats, drinks, and snacks. + +2PM [Mandy Harris Williams](https://www.instagram.com/idealblackfemale/) will lead audiences in the workshop [#BrownUpYourFeed](https://www.instagram.com/explore/tags/brownupyourfeed/) - Getting Fed by Your Feed: An image says a thousand words and reifies hundreds of concepts. An image indicates tens of race, gender and interactive structures in how it is conceived, created, distributed and attended to. This talk/workshop asks us to examine why we follow what we do, and more importantly, how it is serving us. Many of us use Instagram with automaticity, not acknowledging that the images we are feeding ourselves work against our self esteem and value system. How can we design our followed media to sustain and augment our self esteem? + +4-6PM+ DJ Set with [Osagie OG](https://soundcloud.com/osagiebeats). + +Mandy Harris Williams is a theorist, multimedia conceptual artist, writer, educator, and internet/community academic. She is from New York and currently living in Los Angeles. In a nutshell, Mandy's work seeks to get everybody the love that they deserve. She graduated from Harvard, having studied the History of the African Diaspora, as well as the mass incarceration crisis, and other contemporary black issues. She received her MA in Urban Education and worked as a classroom teacher for 7 years. She integrates a holistic didactic style in to her current creative practice. Her creative work has been presented at Paula Cooper Gallery, Navel Gallery, Knockdown Center and Women's Center for Creative Work to name a few. She has contributed writing work to Dazed Magazine, MEL magazine, ForHarriet, and The Grio and is a frequent radio and podcast guest. + +Image: Martine Syms presenting an Artbound episode titled The Mundane Afrofuturist Manifesto, after her work of the same name VIA YOUTUBE \ No newline at end of file diff --git a/_posts/2018-11-18-reza-abdoh-theatre-visionary.md b/_posts/2018-11-18-reza-abdoh-theatre-visionary.md new file mode 100644 index 0000000..438391e --- /dev/null +++ b/_posts/2018-11-18-reza-abdoh-theatre-visionary.md @@ -0,0 +1,17 @@ +--- +layout: post +date: '2018-11-18 13:44 -0500' +published: true +title: 'Reza Abdoh: Theatre Visionary' +event_date: 'Thursday, November 29, 7–8:45pm' +categories: left +--- +![RezaAbdoh.jpg]({{site.baseurl}}/assets/img/RezaAbdoh.jpg) + +Free event: [Ticket reservations are suggested](https://lightboxfilmcenter.org/programs/reza-abdoh-theatre-visionary?fbclid=IwAR0xeKPyG0W6CLQXCBP-RkqZJErNSmJWZq7xG5kzii6w_pUn0ZsF_S2_2Qs) + +"Reza Abdoh: Theatre Visionary" is one of three films presented by Bidoun Projects in conjunction with Publishing As Practice: Bidoun, an experimental publisher-in-residence project hosted by Ulises and funded by the Pew Center for Arts & Heritage. [Bidoun](https://bidoun.org/)——whose work as a nonprofit and former magazine focuses on art and culture from the Middle East and its diasporas——is Ulises’s third publisher resident. The evening will begin with a screening of "Reza Abdoh: Theatre Visionary," a feature length documentary on the pioneering Iranian filmmaker, and conclude with a panel discussion with members of Bidoun. + +Created by Reza Abdoh’s longtime video collaborator and archivist Adam Soch, this documentary builds a vivid portrait of Reza Abdoh through archival footage and recent interviews. Members of the Dar a Luz theater company chronicle the making of successive productions with Abdoh in Los Angeles, New York, and abroad. The film also features the artist’s family, evoking a childhood deeply altered by the history of Abdoh’s native Iran and an adult creative life in America, bearing the scars of the tumultuous 1980s—the decade of Reaganism, the end of the Cold War, and the AIDS epidemic that would eventually take his life. Traversing this cultural divide, Abdoh reflected in a 1994 interview, “I’m just an addict for American culture, and I’m obsessive about it, and it makes me angry. There is so much food for thought and observation in American culture…. I find it very powerful culture, and I like to critique it, and, in a sense, see where it’s heading and where it can go.” + +Adam Soch, US, 2015. 99 min \ No newline at end of file diff --git a/_posts/2018-11-29-bidoun.md b/_posts/2018-11-29-bidoun.md new file mode 100644 index 0000000..d335cea --- /dev/null +++ b/_posts/2018-11-29-bidoun.md @@ -0,0 +1,16 @@ +--- +title: Bidoun +date: 2018-11-29 20:19 -0500 +event_date: November 29, 2018-July 19, 2019 +layout: post +categories: left +published: true +--- +![]({{site.baseurl}}/assets/img/2019_Ulises_Bidoun_Install_Event-4%20(2).jpg) + +For the third and final installment of Publishing as Practice, [Bidoun](https://bidoun.org/) will stage a partial version of its infamous Bidoun Library. Founded in 2009, the Bidoun Library is a presentation of printed matter, carefully selected with zero regard for taste or excellence, that documents the innumerable ways that people have depicted and defined — that is, slandered, celebrated, obfuscated, hyperbolized, ventriloquized, photographed, surveyed, and/or exhumed — the vast, vexed, nefarious construct known as “the Middle East.” + +In addition to publications, the library will have on view a selection of trailers from the little known genre of Iranian-American “B Movies.” Produced mainly in Los Angeles in the years after the revolution, these resolutely un-canonical (and often un-watchable) low budget films feature mainly American casts with a few Iranian actors. They are the direct descendents of filmfarsi, the vernacular B Movie genre that dominated popular Iranian cinema before 1979, and which employed many of the same directors. Much, if not all, was lost in translation. Some of these films were exported to Asia; others have become cult hits among pulp connoisseurs. Seen together, they shape a schizophrenic picture of what these diasporic directors once imagined the formula for a successful Hollywood action film to be. + +- Thursday, November 29, 7pm: Reza Abdoh: Theatre Visionary +- Wednesday, December 5, 6pm: Reza Abdoh’s Showtapes & Short Films diff --git a/_posts/2018-11-29-reza-abdoh-s-showtapes-and-short-films.md b/_posts/2018-11-29-reza-abdoh-s-showtapes-and-short-films.md new file mode 100644 index 0000000..3f84e88 --- /dev/null +++ b/_posts/2018-11-29-reza-abdoh-s-showtapes-and-short-films.md @@ -0,0 +1,28 @@ +--- +layout: post +date: '2018-11-29 20:09 -0500' +published: true +title: Reza Abdoh’s Showtapes and Short Films +categories: left +event_date: 'Wednesday, December 5, 6pm' +--- +![46984668_1984830651600493_4508748683273043968_o.jpg]({{site.baseurl}}/assets/img/46984668_1984830651600493_4508748683273043968_o.jpg) +"Sleeping With the Devil," 1988. USA. Directed by Reza Abdoh + +This screening is at the [ICA Philadelphia](https://icaphila.org/events/48768/) and is free and open to the public, though registration is appreciated. [Register Here](https://icaphila.org/events/48768/) + +"Reza Abdoh: Showtapes and Short Films" is the second of three film screenings presented by Bidoun in conjunction with Publishing As Practice. Bidoun—whose work as a nonprofit and former print magazine focuses on art and culture from the Middle East and its diasporas—is Ulises’s third publisher resident as part of Publishing As Practice. As part of their programming, Bidoun has organized a selection of video excerpts and short films by Iranian-American multimedia artist, Reza Abdoh. + +With his beginnings in experimental theater, Abdoh later took to film and video art, incorporating the same raw energy and subversive imagery that propelled his notoriety as a playwright and director. The fiery intensity of his productions erupts from the erratic choreography and impassioned performances of his casts, fused with his volatile cuts and crude layering of popular culture and iconoclasm. Abdoh sourced and spliced a miscellany of visual motifs, ranging from TV and BDSM to American patriotism and advertisements. His maximalist aesthetic strikes with fervor, weaponizing the anger and alienation experienced by those affected by systemic racism and the AIDS crisis in the United States. + +Compiled by his collaborator Adam Soch, the “showtapes” present segments of Abdoh’s most known theater productions, Hip-Hop Waltz of Eurydice, Bogeyman, The Law of Remains, and Tight White Right (1990–93). As the first video work made by Abdoh following his own HIV diagnosis, Sleeping with the Devil (1988) stitches together screen tests of a multilingual recount of reporter Geraldo Rivera’s interview with cult leader Charles Manson, and probes the potential for empathy through the inflection and delivery of the actors; while Daddy’s Girl (1991) is a lewd and twisted testimony of sexual abuse and violent revenge. The Tryst (1995), a portion of Abdoh’s unfinished second feature, closes the program with the sole footage that was edited by Abdoh before his death and later shown at his memorial, offering a glimpse into a film career tragically cut short. + +Program approx. 60 min. + +Video from the productions The Hip-Hop Waltz of Eurydice, Bogeyman, The Law of Remains, and Tight White Right. 1990–93. USA. Directed by Reza Abdoh. Video design by Adam Soch. 25 min. + +Sleeping with the Devil. 1988. USA. Directed by Reza Abdoh. With Luis Zaldivar, Ken Roht, Michael Whitmore, Anthony Cristian, Paul Durand, Ingrid A., Steve Oglesby. 12 min. + +Daddy’s Girl. 1991. USA. Directed by Reza Abdoh. Cinematography by Adam Soch. With Tony Torn, Juliana Francis. 9 min. + +The Tryst [excerpt from an unfinished film]. 1995. USA. Directed by Reza Abdoh. Cinematography by Tal Yarden. With Tom Fitzpatrick, Tom Pearl, Tony Torn. 7 min. diff --git a/_posts/2019-01-21-michael-c-vazquez-surrealist-self-fashioning.md b/_posts/2019-01-21-michael-c-vazquez-surrealist-self-fashioning.md new file mode 100644 index 0000000..f358b8f --- /dev/null +++ b/_posts/2019-01-21-michael-c-vazquez-surrealist-self-fashioning.md @@ -0,0 +1,16 @@ +--- +layout: post +date: '2019-01-21 21:20 -0600' +published: true +title: 'Michael C. Vazquez: Surrealist Self-Fashioning' +event_date: 'Sunday, January 27, 2–4pm' +categories: left +--- +![50276847_2060641054019452_3595583347029442560_o.jpg]({{site.baseurl}}/assets/img/50276847_2060641054019452_3595583347029442560_o.jpg) +Image: Colette Omogbai, "Agony," 1963. Oil on Hardboard + +Join us on Sunday, January 27 from 2–4 pm for an illustrated lecture by Bidoun Senior Editor Michael C. Vazquez focusing on surrealist self-fashioning. [RSVP HERE](https://www.facebook.com/events/1839609066167763/) + +The paintings of the Nigerian artist Colette Omogbai provoked extreme reactions in the early 1960s, with their vivid, impastoed colors and violently abstracted figures, which conjoined human and animal, life and death. Vazquez explores the contexts on this lost-found artist—given pride of place in Okwui Enwezoor’s 2016 Postwar exhibition—amid other 1960s surrealists in Nigeria, Lebanon, and the United States. + +Michael C. Vazquez is a writer, editor and curator whose primary interests include cultural diplomacy, little magazines, music, intimacy, and food. He is a Senior Editor at Bidoun, an award-winning journal of art, culture, and ideas from the Middle East and elsewhere. Previously he edited Transition: An International Review, a magazine of art and writing about Africa and its many diasporas. He was curator-in-residence for the Delfina Foundation’s inaugural season on “The Politics of Food” and a fellow at the Cullman Center for Scholars and Writers at the New York Public Library. He collaborates frequently with the Colloquium for Unpopular Culture at New York University, and with the artistic working groups Electronic Textures and Women on Airplanes. diff --git a/_posts/2019-02-08-book-release-i-will-what-i-want-women-design-and-empowerment.md b/_posts/2019-02-08-book-release-i-will-what-i-want-women-design-and-empowerment.md new file mode 100644 index 0000000..2115ce4 --- /dev/null +++ b/_posts/2019-02-08-book-release-i-will-what-i-want-women-design-and-empowerment.md @@ -0,0 +1,18 @@ +--- +layout: post +date: '2019-02-08 16:00 -0500' +published: true +title: 'Book Release: I Will What I Want: Women, Design, and Empowerment' +categories: left +event_date: 'Saturday, February 16, 2–4PM' +--- +![51036544_2077928858957338_5925207615930892288_n.jpg]({{site.baseurl}}/assets/img/51036544_2077928858957338_5925207615930892288_n.jpg) + + +The book "I Will What I Want: Women, Design, and Empowerment" accompanied a 2018 exhibition of the same name, which was presented in New York City and Mexico City. In it, design curators Jimena Acosta Romero and Michelle Millar Fisher explore the complex and contradictory role that design has played in shaping women's reproductive agencies since the mid-twentieth century, through second wave feminism, to the non-binary intersections of the present. + +The exhibition presents objects, interfaces, and clothing that has sought to qualify those who have uteruses, menstruate, and/or identify as women as independent and creative subjects in a material world mostly designed by men and for men. + +The book invites the reader to contemplate, from their own perspective, the ways in which these designs have - sometimes for good and at others for bad - governed, shaped, and facilitated their embodied experiences. + +The event is a chance to highlight some of the stories from the book, and engage in audience discussion of this project in the context of several other great recent publications in the same vein. There will be ten copies given away to the first ten visitors who claim them. diff --git a/_posts/2019-03-04-book-launch-faith-wilding-daniel-tucker-and-shannon-stratton.md b/_posts/2019-03-04-book-launch-faith-wilding-daniel-tucker-and-shannon-stratton.md new file mode 100644 index 0000000..ecf0e0f --- /dev/null +++ b/_posts/2019-03-04-book-launch-faith-wilding-daniel-tucker-and-shannon-stratton.md @@ -0,0 +1,23 @@ +--- +layout: post +date: '2019-03-10 10:00 -0500' +published: true +title: 'Book Launch: Faith Wilding, Daniel Tucker, and Shannon Stratton' +event_date: 'Thursday, March 14, 6:30–8PM' +categories: left +--- +![53674801_2119187174831506_8420242654633132032_n.jpg]({{site.baseurl}}/assets/img/53674801_2119187174831506_8420242654633132032_n.jpg) + +Join us for a book signing and discussion centered around the release of "Faith Wilding’s Fearful Symmetries" (Edited by Shannon Stratton for Intellect Books, 2018). + +In keeping with Wilding's own artworks, this book is a bricolage: memoirs and watercolors sit alongside critical essays and family photographs to form an overall history of both Wilding's life and works as well as the wider feminist art movement of the 1970s and beyond. This collection spans fifty years of Wilding’s artistic production, feminist art pedagogy, and participation in, and organizing of, feminist art collectives, such as the Feminist Art Program, Womanhouse, Womanspace Gallery, and the Woman’s Building. Included are contributions by Faith Wilding, Amelia Jones, Mario Ontiveros, Irinaari Starkhova, Jenni Sorkin, Elizabeth Hess, Mira Schor, Keith Vaughn, Lauren Basing, Shannon Stratton and Daniel Tucker. + +For this event, [Wilding](https://en.wikipedia.org/wiki/Faith_Wilding) will engage in a dialogue with former student, Daniel Tucker, following an introduction by Shannon Stratton, curator of Wilding's retrospective, "Faith Wilding: Fearful Symmetries." + +[Shannon R. Stratton](https://en.wikipedia.org/wiki/Shannon_R._Stratton) is an artist, curator, and writer. She cofounded the artist-run organization Threewalls, Chicago, and until recently the William and Mildred Lasdon Chief Curator at the Museum of Arts and Design, New York. + +[Daniel Tucker](https://miscprojects.com/) is an Assistant Professor and Graduate Program Director at Moore College of Art & Design here in Philadelphia. + +Details on the book, [here](https://www.press.uchicago.edu/ucp/books/book/distributed/F/bo31276209.html) + +Image: Faith Wilding; excerpt from ‘Waiting’ performed at Womanhouse, 1972. diff --git a/_posts/2019-03-04-carmen-winant-s-my-birth-book-launch-experimental-lecture.md b/_posts/2019-03-04-carmen-winant-s-my-birth-book-launch-experimental-lecture.md new file mode 100644 index 0000000..cbb99a7 --- /dev/null +++ b/_posts/2019-03-04-carmen-winant-s-my-birth-book-launch-experimental-lecture.md @@ -0,0 +1,19 @@ +--- +layout: post +date: '2019-03-04 10:32 -0500' +published: true +title: 'Carmen Winant''s "My Birth": Book Launch + Experimental Lecture' +categories: left +event_date: 'Thursday, March 7, 6:30–8:30PM' +--- +![]({{site.baseurl}}/assets/img/CarmenWinant.jpg) + +Please join Ulises for an experimental lecture/book launch by artist and writer [Carmen Winant](http://carmenwinant.com/). + +In lieu of a conventional reading or talk, Carmen will deliver a fifteen-minute original script over top of a video that she created — largely looking at the visual content of artists and medical professionals — that acts a compliment to her book, "My Birth." The performance will probe the ways that we see and do not see the experience of childbirth. + +A book of text and image, "My Birth" interweaves photographs of the artist Carmen Winant’s mother giving birth to her three children with found images of other, anonymous, women undergoing the same bodily experience. As the pictorial narrative progresses, from labor through delivery, the women’s postures increasingly blend into one another, creating a collective body that strains and releases in unison. + +In addition to the photographic sequence, "My Birth"—a facsimile of Winant’s own journal—includes an original text by the artist exploring the shared, yet solitary, ownership of the experience of birth. "My Birth" asks: What if birth, long shrouded and parodied by popular culture, was made visible? What if a comfortable and dynamic language existed to describe it? What if, in picturing the process so many times over and insisting on its very subjectivity, we understood childbirth, and its representation, to be a political act? + +In 2018, Carmen Winant participated in the group exhibitions Being: New Photography at the Museum of ModernArt, Another Echo at the Sculpture Center (NY), and a yet-to-be-titled show at the Columbus Museum of Art; solo exhibitions will take place at Miller Contemporary (NY), Stene Projects (Stockholm), and Cave (Detroit). Winant regularly contributes to Aperture, Cabinet, Time, The Believer, and Frieze magazines, and is at work on a book about the nature of practice. diff --git a/_posts/2019-03-16-communists-anonymous-first-gathering-in-philadelphia.md b/_posts/2019-03-16-communists-anonymous-first-gathering-in-philadelphia.md new file mode 100644 index 0000000..fa2b959 --- /dev/null +++ b/_posts/2019-03-16-communists-anonymous-first-gathering-in-philadelphia.md @@ -0,0 +1,18 @@ +--- +layout: post +date: '2019-03-16 16:19 -0400' +published: true +title: 'Communists Anonymous: First Gathering in Philadelphia' +event_date: 'Thursday, March 21, 7pm' +categories: left +--- +![54731340_2134431356640421_3886286576371630080_o.jpg]({{site.baseurl}}/assets/img/54731340_2134431356640421_3886286576371630080_o.jpg) + +Join the first gathering of Communists Anonymous in Philadelphia, a celebration of the constitutive book "Solution 275–294: Communists Anonymous" (edited by Ingo Niermann and Joshua Simon, Sternberg Press, 2017), with Hammam Aldouri, Mark Johnson, Pavel Khazanov, Kate Kraczon, Marina McDougall Vella, Joshua Simon, Helen Stuhr-Rommereim, and everyone interested in sharing their relations to communisms present, past, and future. + +The members of Communists Anonymous (COMA) suffer from an incurable belief in communism. They don’t share any particular school, but they do share an extreme sense of empathy and justice, and therefore detest more or less any form of private property. Because there is currently no communist state in existence, acting out their passion would hopelessly distress them, at best curbing and stabilizing the brutalities of capitalist society. + +COMA is meant to evolve into a worldwide cluster of self-help groups where incurable communists can discuss their recent temptations and relapses in the futile fight against capitalism. COMA’s “fearless moral inventory” challenges the historical manifestations of communism as being substantially incomplete in thought and practice and places communism again where it originates—in the realm of fiction. COMA believes that the most vital dialectics in human history are at play in fiction contradicting reality. Only as fiction can communism manifest itself again beyond doubt. + +"Solution 275–294 Communists Anonymous," Ingo Niermann, Joshua Simon (Eds.) +Contributions by Santiago Alba Rico, Heather Anderson, Ann Cotten, Fiona Duncan, Anthony Dunne and Fiona Raby, Boris Groys, Elfriede Jelinek, Georgy Mamedov and Oksana Shatalova, Metahaven, Momus, Ingo Niermann, David Pearce, Frank Ruda, Georgia Sagri, Joshua Simon, Alexander Tarakhovsky, Timotheus Vermeulen diff --git a/_posts/2019-03-25-genderfail-conditioner-launch.md b/_posts/2019-03-25-genderfail-conditioner-launch.md new file mode 100644 index 0000000..851f97a --- /dev/null +++ b/_posts/2019-03-25-genderfail-conditioner-launch.md @@ -0,0 +1,21 @@ +--- +layout: post +date: '2019-03-25 10:43 -0400' +published: true +title: GenderFail "Conditioner" Publication Launch +categories: left +event_date: 'Sunday, March 31, 2–4PM' +--- +![54379024_2140529272697296_8002580552798437376_o.jpg]({{site.baseurl}}/assets/img/54379024_2140529272697296_8002580552798437376_o.jpg) + +Please join Ulises for a publication release and reading event for "Conditioner" a new publication by artist [Liz Barr](https://liz-barr.com/) through [GenderFail Press](https://www.genderfail.space/). Barr will be joined by writers Meg Pendoley and Blanche Brown in a series of readings for the event. + +"Conditioner" considers women's sense of alienation from their bodies, caused by gender norms and beauty ideals, and the ways that the wellness and skincare industries either alleviate or exacerbate that alienation. Conditioner explores the nuances of the subject, accounting for the history of American cosmetics and skincare, as well as the ways that preceding feminist movements have addressed them. This is Barr's second publication with GenderFail. + +**[Liz Barr](https://liz-barr.com/)** is an interdisciplinary artist based in West Philadelphia. She makes work about bodies and how we build them. Her zines can be found in libraries and bookstores in Philadelphia and elsewhere, including at Printed Matter, Inc.; Artbook at MoMA PS1; Quimby's; and Ulises. + +**Meg Pendoley** is a writer living in Philadelphia. She's interested in queer homes (bodies, houses, neighborhoods), the boundaries they share, and how what happens there might be recorded and kept. Her work appears in Apiary, Cleaver, and Tin House's Open Bar. + +**Blanche Brown** is a poet from north Florida. She is finishing up temple's MFA program and owns two oyster knives. + +**[GenderFail](https://www.genderfail.space/)** is a publishing and programming initiative that seeks to encourage projects that foster an intersectional queer subjectivity. GenderFail embraces failure as a site of cultural production. GenderFail has been apart of exhibitions, programs and events at MoMA PS1 (Long Island City), The International Center of Photography (NYC), Wendy's Subway (Brooklyn), Studio Museum (Harlem), William College Museum of Art (Williamstown), Vox Populi (Philadelphia), EFA Project Space (NYC) and many others. diff --git a/_posts/2019-04-02-2019-common-field-philadelphia-convening.md b/_posts/2019-04-02-2019-common-field-philadelphia-convening.md new file mode 100644 index 0000000..d31e81d --- /dev/null +++ b/_posts/2019-04-02-2019-common-field-philadelphia-convening.md @@ -0,0 +1,25 @@ +--- +layout: post +date: '2019-04-02 22:58 -0400' +published: true +title: 2019 COMMON FIELD PHILADELPHIA CONVENING +event_date: 'April 25-28, 2019' +categories: left +--- + +![commonfield_facebook_post_3.png]({{site.baseurl}}/assets/img/commonfield_facebook_post_3.png) + +Ulises is proud to announce our partnership with [Common Field](https://www.commonfield.org/convenings/) — a national network of experimental, independent, visual arts organizations and organizers — to bring the annual Convening to Philadelphia, PA from April 25–28, 2019. The Common Field Convening is an itinerant gathering that brings together 500+ local and national arts organizers to explore the state of the field of artists organizations and to share resources, knowledge and methods for artist-led, artist-run, and artist-centered projects, spaces and practices. + +Over the past year, Common Field has worked with Ulises as part of a group of 14 local organizing partners as well as a growing network of 80+ Philadelphia arts organizations and organizers in order to connect the local contexts and conditions with the interests of the national Common Field Network. + +As a platform for gathering the many artist centered organizations, the Convening recognizes the value of their contributions as a critical and central part of the city’s cultural fabric. It builds awareness for these practices that often take place in unique contexts, and serve and represent more diverse communities. Together we understand there is an urgency to gather around issues of social justice and equity, as well as practical needs and tools for many organizations in our network. + +Find out more about the Convening and get your tickets [online](https://www.commonfield.org/convenings/1949/2470/tickets). +Check out the program, presenters and full [schedule](https://www.commonfield.org/convenings/1949/program/). +Follow Common Field on social media ([IG](https://www.instagram.com/common_field/) | [FB](https://www.facebook.com/commonfield/) | [TW](https://twitter.com/Common_Field)) and sign up for their [newsletter](https://www.commonfield.org/news/) for regular updates. + +Friends Center, Center City, Philadelphia, PA +[commonfield.org/convenings](https://www.commonfield.org/convenings/) +[Facebook RSVP](https://www.facebook.com/events/714972885567466/) +#CommonFieldPhilly diff --git a/_posts/2019-07-10-screening-reza-abdoh-s-the-blind-owl.md b/_posts/2019-07-10-screening-reza-abdoh-s-the-blind-owl.md new file mode 100644 index 0000000..2bc9535 --- /dev/null +++ b/_posts/2019-07-10-screening-reza-abdoh-s-the-blind-owl.md @@ -0,0 +1,17 @@ +--- +layout: post +date: '2019-07-10 10:52 -0400' +published: true +title: 'Screening: Reza Abdoh''s The Blind Owl' +categories: left +event_date: ' Thursday, July 18, 6–8 PM' +--- +![The Blind Owl Still with Ron Athey.jpg]({{site.baseurl}}/assets/img/The Blind Owl Still with Ron Athey.jpg) + +"The Blind Owl" Still with Ron Athey + +Please join us for a screening of Reza Abdoh's "The Blind Owl" along with an introduction by Bidoun Senior Editor Michael C. Vazquez. This will be the final program presented by Bidoun in conjunction with Publishing As Practice, an experimental publisher-in-residence project hosted by Ulises and funded by the Pew Center for Arts & Heritage. + +Reza Abdoh was celebrated for his immersive and maximalist theatre productions, which drew on Greek myth, cable television, BDSM and fairy tales, and made use of unusual urban spaces and audio-visual media. Yet had Abdoh not passed away at the too-young age of thirty-two, he almost certainly would have become a filmmaker of renown. + +"The Blind Owl" (1992) is Abdoh’s only complete feature film. Shot in and around East Los Angeles with members of his Dar a Luz theatre ensemble between performances of the play Bogeyman (1991), the film provides a curious counterpoint to Abdoh’s immersive, maximalist, adrenaline-fueled theater productions. Its narrative explores abjection, illness, and belonging through a diverse cast of characters, including sex workers, a diabetic mortician and his caregiver, and a blind man and his disabled transgender companion. The Blind Owl unfurls amid an atmosphere of melancholy that, although often moving, is wholly devoid of affect. The film’s slow, meditative pacing and contemplative posture have inspired comparisons to theater director Robert Wilson’s symbolist work, the films of Robert Bresson, and the 1960s American TV show, The Outer Limits. \ No newline at end of file diff --git a/_posts/2019-08-17-art-labor-what-next-after-a-summer-of-struggle.md b/_posts/2019-08-17-art-labor-what-next-after-a-summer-of-struggle.md new file mode 100644 index 0000000..9212591 --- /dev/null +++ b/_posts/2019-08-17-art-labor-what-next-after-a-summer-of-struggle.md @@ -0,0 +1,18 @@ +--- +layout: post +date: '2019-08-17 15:02 -0400' +published: true +title: 'Art and Labor: What''s Next After a Summer of Struggle? ' +event_date: 'Thursday, August 29, 6–8pm' +categories: left +--- +![Screen Shot 2019-08-17 at 4.02.28 PM.png]({{site.baseurl}}/assets/img/Screen Shot 2019-08-17 at 4.02.28 PM.png) + +This a very particular moment of change for the art and museum field. Agitating around issues of part-time contracts, workplace safety, lack of benefits, and equity across different vectors, recent months have witnessed a wave of unionizing, landmark labor discrimination lawsuits, public salary sharing, and work for equity of representation of critics and cultural voices, amongst other highly visible and completely invisible work. + +What comes next after this summer of struggle? Join the conversation, moderated by Michelle Fisher, on behalf of [Art + Museum Transparency](https://twitter.com/amtransparency?lang=en). She'll be joined by New Museum's Dana Kopel, Drew Ambrogi of Coworker.org, independent curator Chaédria LaBouvier, and Sara Ziff founder of Model Alliance. + +[RSVP](https://www.facebook.com/events/866554137061433/), Free to attend! +If you can, help us out by bringing a snack, or drink, or chair. + +Current and former employees of art institutions started sharing the terms and salaries of their employment in a public Google Spreadsheet titled “Art/Museum Salary Transparency 2019," started by Michelle. You can [view the spreadsheet here](https://docs.google.com/spreadsheets/d/14_cn3afoas7NhKvHWaFKqQGkaZS5rvL6DFxzGqXQa6o/edit#gid=0) and add your information through [this form](https://docs.google.com/forms/d/e/1FAIpQLSfYV_efuUiEG8BnuD1_XwLaY7bEjsBgYxeWs3nFcP4sAQAC_w/viewform). diff --git a/_posts/2019-09-19-ny-art-book-fair.md b/_posts/2019-09-19-ny-art-book-fair.md new file mode 100644 index 0000000..63152fc --- /dev/null +++ b/_posts/2019-09-19-ny-art-book-fair.md @@ -0,0 +1,18 @@ +--- +layout: post +date: '2019-09-19 12:32 -0400' +published: true +title: NY Art Book Fair +categories: left +event_date: 'September 19–22, 2019' +--- +![IMG_3634.jpg]({{site.baseurl}}/assets/img/IMG_3634.jpg) + +Ulises Location: N37 (2nd Floor) +[More information (Hours, Access etc.)](https://nyabf2019.printedmatterartbookfairs.org/About) + +Initiated in 2005, Printed Matter’s NY Art Book Fair (NYABF) is the leading international gathering for the distribution of artists’ books, celebrating the full breadth of the art publishing community. + +Held at MoMA PS1 in Long Island City, the 2019 NY Art Book Fair will host 369 exhibitors from 31 countries, including a broad range of artists and collectives, small presses, institutions, galleries, antiquarian booksellers, and distributors. Free and open to the public, the event draws more than 40,000 individuals including book lovers, collectors, artists, and art world professionals each year. With a commitment to diversity and representation, the fair will serve as a meeting place for an extended community of publishers and book enthusiasts, as well as a site for dialogue and exchange around all facets of arts publishing. + +Books Books Books! \ No newline at end of file diff --git a/_posts/2019-09-19-the-school-for-temporary-liveness-reading-room.md b/_posts/2019-09-19-the-school-for-temporary-liveness-reading-room.md new file mode 100644 index 0000000..cffc396 --- /dev/null +++ b/_posts/2019-09-19-the-school-for-temporary-liveness-reading-room.md @@ -0,0 +1,24 @@ +--- +layout: post +date: '2019-09-24 12:31 -0400' +published: true +title: 'The School for Temporary Liveness, Reading Room' +event_date: 'September 25 – October 2, 2019' +categories: left +--- +![Screen Shot 2019-09-19 at 2.29.22 PM.png]({{site.baseurl}}/assets/img/Screen Shot 2019-09-19 at 2.29.22 PM.png) + +[The School for Temporary Liveness](https://temporaryliveness.org/) is a week-long series of performances, workshops, talks, conversations and new formats for study inhabiting the poetic frame of a school. The School comprises three zones of encounter—The Classroom, The Library, and Study Hall—each of which engage different modes of viewing and participation. + +Ulises will be participating as part of [Study Hall](https://temporaryliveness.org/study-hall), setting up a Reading Room on he 3rd floor and asking you to think about how might the performance of the body inform our understanding of the circulation of books? Ulises invites you to a room for reading and reflection open throughout the duration of the School for Temporary Liveness. Housed within the Study Hall, the reading room will gather texts that inform and extend from the School for Temporary Liveness’s curriculum and participating practitioners. + +Ulises will also host a pop-up shop during select hours. Browse a selection of domestic and international titles—including independent art publications and artists’ books—on critical theory, embodied practice, Black radical thought and other concepts key to the School for Temporary Liveness. + +The Reading Room is always open. Shop Hours: +Wednesday, Sept. 25, 6–7pm; +Friday, Sept. 27, 6–8pm; +Saturday, Sept. 28, 4–8pm; +Sunday, Sept. 29, 12-4pm; +Wednesday, Oct. 2, 4-8pm. + +This school is free and for the public. Anyone can be a student. STL is presented by University of the Arts School of Dance and has been supported by The Pew Center for Arts & Heritage. diff --git a/_posts/2019-11-03-the-big-move-party.md b/_posts/2019-11-03-the-big-move-party.md new file mode 100644 index 0000000..6903576 --- /dev/null +++ b/_posts/2019-11-03-the-big-move-party.md @@ -0,0 +1,15 @@ +--- +layout: post +date: '2019-11-03 16:33 -0500' +published: true +title: The Big Move Party +event_date: 'Saturday, November 9, 2019' +categories: left +--- +![IMG_4418.JPG]({{site.baseurl}}/assets/img/IMG_4418.JPG) + +Join the Ulises team in celebrating our 3 year anniversary and a big move! The books and furniture are already gone, so bring dancing shoes. There will be drinks and movin and groovin as we embrace change and remember so many great moments in the old garage-turned bookstore. Tunes to move to by DJ Mier Mier Mier Mier Mier (Jamier Bieber Snell) & jay plus. + +We are saying goodbye to our 31 E Columbia Ave location but are going to be plenty busy with pop-ups and planning a new spot, to open early 2020. + + diff --git a/_posts/2019-11-03-when-the-whirlwind-begins.md b/_posts/2019-11-03-when-the-whirlwind-begins.md new file mode 100644 index 0000000..8c18f71 --- /dev/null +++ b/_posts/2019-11-03-when-the-whirlwind-begins.md @@ -0,0 +1,26 @@ +--- +layout: post +date: '2019-11-03 16:50 -0500' +published: true +title: When the Whirlwind Begins +event_date: 'November 8–December 11, 2019' +categories: left +--- +![PHILLY_SHOW_FINAL-11x17-forweb.jpg]({{site.baseurl}}/assets/img/PHILLY_SHOW_FINAL-11x17-forweb.jpg) + +We're excited to be included in [_When the Whirlwind Begins_ at The Anderson Gallery](https://arts.vcu.edu/programs/theanderson/) at Virgina Commonwealth University. The group show, curated by students explores turmoil and disaster, but aslso new love and beginnings. The Anderson Gallery at VCU is an exhibition and program space for the VCUarts community. It supports experimentation, professional development and work across disciplines. Opening Reception: Nov. 8, 6–9pm! + +Marie Alarcon, +Anthony Campuzano, +Alex Da Corte, +Dufala Bros., +Claes Gabriel, +Erlin Geffard, +Adam Lovitz, +James Maurelle, +Angela McQuillan, +Kat Richards, +Patricia Thomas, and +Ulises + +Poster by [J. S. Wright](https://www.instagram.com/liver_ideas/) \ No newline at end of file diff --git a/_posts/2019-12-01-odds-and-ends-art-book-fair.md b/_posts/2019-12-01-odds-and-ends-art-book-fair.md new file mode 100644 index 0000000..54077d0 --- /dev/null +++ b/_posts/2019-12-01-odds-and-ends-art-book-fair.md @@ -0,0 +1,12 @@ +--- +layout: post +date: '2019-12-01 12:01 -0500' +published: true +title: Odds and Ends +event_date: 'Friday, December 6, 2019' +categories: left +--- +![GRAPHIC_Odds_2019_v2.jpg]({{site.baseurl}}/assets/img/GRAPHIC_Odds_2019_v2.jpg) + + +See you at the Odds and Ends Art Book Fair at the [Yale University Art Gallery](https://artgallery.yale.edu/calendar/events/odds-and-ends-art-book-fair), Friday, December 6th, 11:30 am-4:30 pm — Free and Open to the Public! diff --git a/_posts/2019-12-01-publishing-as-practice.md b/_posts/2019-12-01-publishing-as-practice.md new file mode 100644 index 0000000..e8ed7d7 --- /dev/null +++ b/_posts/2019-12-01-publishing-as-practice.md @@ -0,0 +1,43 @@ +--- +title: Publishing As Practice +date: 2019-12-01 21:48 -0500 +event_date: 2017–2019 +layout: post +categories: right +published: true +--- +![Publishing as Practice Book animated gif](/assets/img/pasp.gif ) + + + +Edited by Ulises: Kayla Romberger, Gee Wesley, Nerissa Cooney, Lauren Downing, and Ricky Yanas\ +Co-published by: Inventory Press & Ulises\ +Design by: Joel Evey & David Wise +{: .no-indent} + +7 ¾ × 10 inches, 176 pages\ +ISBN 978-1-941753-40-8 +{: .no-indent} + +$35.00 +{: .no-indent} + +

order now

+ +*Publishing as Practice: Hardworking Goodlooking, Martine Syms/Dominica, Bidoun* centers on the work of three contemporary artists/book publishers who have developed fresh ways of broaching the political in publishing. + +This book documents a residency program at Ulises—a curatorial platform based in Philadelphia—that explores publishing as an incubator for new forms of editorial, curatorial and artistic practice. Over the course of two years, three participants (Hardworking Goodlooking, Martine Syms/Dominica, and Bidoun) activated Ulises as an exhibition space and public programming hub, engaging the public through workshops, discussions, and projects. + +Hardworking Goodlooking is a design and publishing imprint working primarily out of the Philippines. Dominica is an imprint run by artist Martine Syms dedicated to exploring Blackness as a topic, reference, marker, and audience in visual culture. Bidoun, a non-profit organization and magazine, focuses on art and culture from the Middle East and its diasporas. Each organization approached their residency at Ulises in a unique way, bringing a new understanding of what it means to practice publishing. + +Edited by Kayla Romberger, Gee Wesley, Nerissa Cooney, Lauren Downing, and Ricky Yanas, *Publishing as Practice* features a preface by David Senior, Head of Library and Archives at the San Francisco Museum of Modern Art, and Ulises Carrión’s 1975 publishing manifesto “The New Art of Making Books.” *Publishing as Practice* also includes writing from Clara Balaguer, Hardworking Goodlooking, Martine Syms/Dominica, Bidoun, Lauren Downing, Kayla Romberger, and Gee Wesley alongside interviews, excerpts, and documentation from each residency. + +{% comment %} + +Publishing As Practice, a three-part publisher residency designed to explore publishing as an incubator for new forms of editorial, curatorial, and artistic practice. Three experimental art publishers activated Ulises from 2017-19 as an exhibition space and public programming hub, engaging the public through workshops, discussions, and projects. + +Residents included [Hardworking Goodlooking](https://www.instagram.com/hardworkinggoodlooking/?hl=en), the publishing arm of Philippines-based, social practice platform The Office of Culture and Design; [Dominica](https://dominica.la/), an imprint run by Martine Syms dedicated to exploring blackness as a topic, reference, marker and audience in visual culture; and [Bidoun](https://www.bidoun.org/), a non-profit organization focused on art and culture from the Middle East and its diasporas. + +[PRE-ORDER](https://ulises.pmvabf.org/) *Publishing As Practice: Hardworking Goodlooking, Martine Syms/Dominica, Bidoun* + +{% endcomment %} \ No newline at end of file diff --git a/_posts/2020-01-25-sci-fi-sunday-reading-at-pma.md b/_posts/2020-01-25-sci-fi-sunday-reading-at-pma.md new file mode 100644 index 0000000..acfbab4 --- /dev/null +++ b/_posts/2020-01-25-sci-fi-sunday-reading-at-pma.md @@ -0,0 +1,15 @@ +--- +layout: post +date: '2020-01-25 15:30 -0500' +published: true +title: 'Sci-Fi Sunday, Reading' +categories: left +event_date: 'Sunday, January 26, 2020, 2–3pm' +--- +![IMG_5664.JPG]({{site.baseurl}}/assets/img/IMG_5664.JPG) + +Representing Ulises for [Sci-Fi Sunday at the PMA](https://philamuseum.org/calendar/event/sci-fi-sunday-ulises), poet and artist Anaïs Duplan will share some of his favorite passages from Colson Whitehead’s The Intuitionist. The Sci-Fi Sunday reading series is in conjunction with the exhibition “Designs for Different Futures.” + +[Anaïs Duplan](https://worksofanais.com/) is the founding curator for the Center for Afrofuturist Studies, an artist residency program for artists of color, based in Iowa City. He now works as Program Manager at Recess and Adjunct Assistant Professor in Poetry at Columbia University. + +The Intuitionist concerns the travails of Lila Mae Watson, the first black woman elevator inspector in a New York-esque city. The novel seizes upon an unsung wonder in our midst, the elevator, and sings its history, its technology, its romance, adding to the novelist’s solid research a scintillating pinch of sci-fi fantasy. The extensive guild of metropolitan elevator inspectors is split, it would seem, between the Empiricists, who plod through their inspections one material criterion at a time, and the Intuitionists, who take a more mystical, gestalt approach to the detection of safety flaws. \ No newline at end of file diff --git a/_posts/2020-05-28-press-play-live.md b/_posts/2020-05-28-press-play-live.md new file mode 100644 index 0000000..54d7ad5 --- /dev/null +++ b/_posts/2020-05-28-press-play-live.md @@ -0,0 +1,19 @@ +--- +layout: post +date: '2020-05-29 7:30 -0400' +published: true +title: Press Play — LIVE! +categories: left +event_date: 'Sunday, May 31, 2–4PM' +--- +![press_play_flyer (3).jpg]({{site.baseurl}}/assets/img/press_play_flyer (3).jpg) + +[Register](https://moorecad.zoom.us/meeting/register/tJUodOisqDMoG9wVU75dJv8fwr4yl5tF7oh-) + +Looking forward to participating in FORTUNE's online panel with other QT/POC-run small presses and print spaces, including No Shame Distro, Sponge Gourd Collective, Endless Editions, and Other Publishing to discuss print resources and futures. + +As we come together toward an uncertain future, we hope to ground ourselves in print as an act of resource-sharing, of radical gathering, of material resilience — something to hold on to. Join us as we connect with print collectives to share experiences and best practices for inspired, sustainable, accessible, and community-oriented work. + +What are the strategies, sources of support, and print forebears on which we can lean? How do we continue to document this coming-together? + +This program is part of FORTUNE’s archival practice during the Year of the Rat. Project support provided by The Velocity Fund administered by Temple Contemporary at Tyler School of Art and Architecture, Temple University with generous funding from The Andy Warhol Foundation for the Visual Arts. diff --git a/_posts/2020-07-29-a-certain-kind-of-space-how-we-sustain-each-other.md b/_posts/2020-07-29-a-certain-kind-of-space-how-we-sustain-each-other.md new file mode 100644 index 0000000..bbae449 --- /dev/null +++ b/_posts/2020-07-29-a-certain-kind-of-space-how-we-sustain-each-other.md @@ -0,0 +1,17 @@ +--- +layout: post +date: '2020-07-29 09:59 -0400' +published: true +title: 'A Certain Kind of Space: How We Sustain Each Other' +categories: left +--- +![_MG_6884 (1).jpg]({{site.baseurl}}/assets/img/_MG_6884 (1).jpg) + +A Certain Kind of Space: How We Sustain Each Other was part of Common Field's 2020 Online Convening. [Watch the video here](https://www.commonfield.org/convenings/3248/documentation/4170/a-certain-kind-of-space-how-we-sustain-each-other)! + +Building on previous convening dialogues, presenters ask each other and audience members: How do economics, location, size, and identity shape an artist collective and impact decision making? Who gets to take part? Given the long history of grassroots organizing by artists, why be an artist-run organization in 2020? + +What does it mean for artistic spaces to survive the current capitalist economic system we work under? Members of artist-run collectives Grizzly Grizzly, Living Room Light Exchange, ‘sindikit, and Ulises openly discuss how organizational development in itself has become a creative practice, and how that informs their accountability to the artists and the communities they engage. Running an organization often means interacting with, and subverting, an economic system. What is the impact of working this way? This conversation places independent organizations from various geographic locations, which are negotiating different constraints, in dialogue to expand practical strategies for survival, stewardship, and conceptual engagement. + +- [Common Field Convening](https://www.commonfield.org/convenings/3248/documentation/4170/a-certain-kind-of-space-how-we-sustain-each-other) +- [Archival Video](https://vimeo.com/419445780) diff --git a/_posts/2020-10-14-register-and-vote.md b/_posts/2020-10-14-register-and-vote.md new file mode 100644 index 0000000..7f09f61 --- /dev/null +++ b/_posts/2020-10-14-register-and-vote.md @@ -0,0 +1,11 @@ +--- +layout: post +date: '2020-10-14 15:52 -0400' +published: true +title: REGISTER AND VOTE +categories: left +event_date: 'November 3, 2020' +--- +![jenny-holzer-plan-your-vote-animations-info-1.jpg]({{site.baseurl}}/assets/img/jenny-holzer-plan-your-vote-animations-info-1.jpg) + +Philly, we're in a swing state and October 19th is the last day to register in PA, so check your registration status and [plan your vote](https://www.youvote.vote/)! To help spread the word, artist Jenny Holzer has created a series of animations some of which you can [download here](https://egnyte.suttoncomms.com/fl/a58QLENKUd#folder-link/). Enough is enough is enough. diff --git a/_posts/2021-02-05-pmvabf.md b/_posts/2021-02-05-pmvabf.md new file mode 100644 index 0000000..719b770 --- /dev/null +++ b/_posts/2021-02-05-pmvabf.md @@ -0,0 +1,19 @@ +--- +layout: post +date: '2021-02-05 10:53 -0500' +published: true +title: Printed Matter Virtual Art Book Fair +event_date: 'February 24–28, 2021' +categories: left +--- +![b85775fd-4335-47fa-ba25-80c6c9a901b1.JPG]({{site.baseurl}}/assets/img/b85775fd-4335-47fa-ba25-80c6c9a901b1.JPG) + + +- Wednesday, February 24 (Opening & Preview)  +- Thursday, February 25–Sunday, February 28 (Fair Days) +- Saturday, February 27, 11am EST ([Classroom Conversation](https://pmvabf.org/The-Classroom-Friendly-Fire)) + +This year Printed Matter Book Fair is going virtual, visit Ulises along with more than 400 exhibitors from over 40 countries. We're excited to announce that our first book, _Publishing A Practice: Hardworking Goodlooking, Martine/Syms, Bidoun_, co-published with Inventory Press, is available for [pre-order](https://ulises.pmvabf.org/)! Also, join the Ulises team for a Classroom conversation with Publishing As Practice residents, Clara Balaguer, Dante Carlos, and Kristian Henson of Hardworking Goodlooking on Saturday, Febuary 27 at 11am EST. + +[Portal to the virtual fair](https://ulises.pmvabf.org/) + diff --git a/_posts/2021-04-29-publishing-as-practice.md b/_posts/2021-04-29-publishing-as-practice.md new file mode 100644 index 0000000..f62bed8 --- /dev/null +++ b/_posts/2021-04-29-publishing-as-practice.md @@ -0,0 +1,45 @@ +--- +title: Publishing As Practice +date: 2019-12-01 21:48 -0500 +event_date: Hardworking Goodlooking, Martine Syms/Dominica, Bidoun +layout: post +categories: left +tags: + - sticky + - mobile-only +published: true +--- + +![Publishing as Practice Book animated gif](/assets/img/pasp.gif) + +Edited by Ulises: Kayla Romberger, Gee Wesley, Nerissa Cooney, Lauren Downing, and Ricky Yanas\ +Co-published by: Inventory Press & Ulises\ +Design by: Joel Evey & David Wise +{: .no-indent} + +7 ¾ × 10 inches, 176 pages\ +ISBN 978-1-941753-40-8 +{: .no-indent} + +$35.00 +{: .no-indent} + +

ORDER NOW

+ +_Publishing as Practice: Hardworking Goodlooking, Martine Syms/Dominica, Bidoun_ centers on the work of three contemporary artists/book publishers who have developed fresh ways of broaching the political in publishing. + +This book documents a residency program at Ulises—a curatorial platform based in Philadelphia—that explores publishing as an incubator for new forms of editorial, curatorial and artistic practice. Over the course of two years, three participants (Hardworking Goodlooking, Martine Syms/Dominica, and Bidoun) activated Ulises as an exhibition space and public programming hub, engaging the public through workshops, discussions, and projects. + +Hardworking Goodlooking is a design and publishing imprint working primarily out of the Philippines. Dominica is an imprint run by artist Martine Syms dedicated to exploring Blackness as a topic, reference, marker, and audience in visual culture. Bidoun, a non-profit organization and magazine, focuses on art and culture from the Middle East and its diasporas. Each organization approached their residency at Ulises in a unique way, bringing a new understanding of what it means to practice publishing. + +Edited by Kayla Romberger, Gee Wesley, Nerissa Cooney, Lauren Downing, and Ricky Yanas, _Publishing as Practice_ features a preface by David Senior, Head of Library and Archives at the San Francisco Museum of Modern Art, and Ulises Carrión’s 1975 publishing manifesto “The New Art of Making Books.” _Publishing as Practice_ also includes writing from Clara Balaguer, Hardworking Goodlooking, Martine Syms/Dominica, Bidoun, Lauren Downing, Kayla Romberger, and Gee Wesley alongside interviews, excerpts, and documentation from each residency. + +{% comment %} + +Publishing As Practice, a three-part publisher residency designed to explore publishing as an incubator for new forms of editorial, curatorial, and artistic practice. Three experimental art publishers activated Ulises from 2017-19 as an exhibition space and public programming hub, engaging the public through workshops, discussions, and projects. + +Residents included [Hardworking Goodlooking](https://www.instagram.com/hardworkinggoodlooking/?hl=en), the publishing arm of Philippines-based, social practice platform The Office of Culture and Design; [Dominica](https://dominica.la/), an imprint run by Martine Syms dedicated to exploring blackness as a topic, reference, marker and audience in visual culture; and [Bidoun](https://www.bidoun.org/), a non-profit organization focused on art and culture from the Middle East and its diasporas. + +[ORDER NOW](https://ulises.pmvabf.org/) _Publishing As Practice: Hardworking Goodlooking, Martine Syms/Dominica, Bidoun_ + +{% endcomment %} diff --git "a/_posts/2022-03-23-out-loud-readings-and-videos-with-wendy\342\200\231s-subway-and-futurepoem.md" "b/_posts/2022-03-23-out-loud-readings-and-videos-with-wendy\342\200\231s-subway-and-futurepoem.md" new file mode 100644 index 0000000..ca06ae5 --- /dev/null +++ "b/_posts/2022-03-23-out-loud-readings-and-videos-with-wendy\342\200\231s-subway-and-futurepoem.md" @@ -0,0 +1,26 @@ +--- +title: "Out Loud: Readings and Videos with Wendy’s Subway and Futurepoem" +date: 2022-03-23T02:11:04.650Z +event_date: Friday, March 25, 2022 at 7pm +layout: post +categories: left +published: true +--- + + +![](/assets/img/out_loud_web.jpeg) + +Ulises is excited to welcome [Wendy’s Subway](https://wendyssubway.com/) and [Futurepoem](https://www.futurepoem.com/), who will present readings by Vidhu Aggarwal, Mirene Arsanios, Imani Elizabeth Jackson, Jessica Laser, and Ronaldo V. Wilson on the occasion of the 2022 AWP Conference (Association of Writers and Writing Programs).  The program also includes a screening of recent videos by Wendy’s Subway authors JJJJJerome Ellis, Jaamil Olawale Kosoko, and Shala Miller. + +Recent/Forthcoming books: + +* Vidhu Aggarwal, [Daughter Isotope](https://www.theoperatingsystem.org/product/daughter-isotope/) (The Operating System, 2021) +* Mirene Arsanios, The Autobiography of a Language (Futurepoem, 2022) +* JJJJJerome Ellis, [The Clearing](http://wendyssubway.com/publishing/titles/the-clearing) (Wendy’s Subway, 2021) +* Imani Elizabeth Jackson, Flag (Futurepoem, 2022) +* Jaamil Olawale Kosoko, [Black Body Amnesia: Poems and Other Speech Acts](http://wendyssubway.com/publishing/titles/black-body-amnesia) (Wendy’s Subway, 2022) +* Jessica Laser, Planet Drill (Futurepoem, 2022) +* Shala Miller, [Tender Noted](https://www.wendyssubway.com/publishing/titles/tender-noted) (Wendy’s Subway, 2022) +* Ronaldo V. Wilson, [Carmelina: Figures](https://www.wendyssubway.com/publishing/titles/carmelina-figures) (Wendy’s Subway, 2021) + + Location: Icebox Project Space, 1400 N American Street, Philadelphia, PA 19122 \ No newline at end of file diff --git a/_posts/2022-06-10-publication-release-with-first-last-x-quick-books.md b/_posts/2022-06-10-publication-release-with-first-last-x-quick-books.md new file mode 100644 index 0000000..96e66b8 --- /dev/null +++ b/_posts/2022-06-10-publication-release-with-first-last-x-quick-books.md @@ -0,0 +1,13 @@ +--- +title: First Last x Quick Books Publication Release +date: 2022-06-10T14:00:23.058Z +event_date: Saturday, June 25, 2022 at 2pm +layout: post +categories: left +published: true +--- + + +![](/assets/img/qbxfl_04.jpg) + +[First Last](https://firstlast.us/) and [Quickbooks](http://quick-books.biz/) are releasing a special edition collaboration publication featuring [Mickey Aloisio](https://www.mickeyaloisio.com/) & [Ryan Skrabalak](https://www.poetryproject.org/people/ryan-skrabalak). A FREE publication about moving around, trucks and cars, donuts and dudes. \ No newline at end of file diff --git a/_posts/2022-06-22-big-summer-book-sale.md b/_posts/2022-06-22-big-summer-book-sale.md new file mode 100644 index 0000000..103fa0f --- /dev/null +++ b/_posts/2022-06-22-big-summer-book-sale.md @@ -0,0 +1,33 @@ +--- +title: Big Summer Book Sale +date: 2022-06-22T16:50:44.237Z +event_date: Saturday, July 16, 2022 from 12–6pm +layout: post +categories: left +published: true +--- +![](/assets/img/ulises-sale_ig_01-06.jpg) + +Ulises in collaboration with Icebox Project Space and FORTUNE presents the Big Summer Book Sale! Come for the sale and stay for the snacks, drinks, and good afternoon vibes featuring DJ Rana Ransom.  + +Books and prints and goods from our friends: + +* [All Caps Studio](https://www.allcapstudio.com/) +* [Amze Emmons](https://www.amzeemmons.com/new-page) +* [Iffy Books](https://iffybooks.net/) +* [Kamihira](https://www.instagram.com/kamihira.us/?hl=en) +* [Justine Kelley](https://www.justine-kelley.com/) +* [Lot 49 Books](https://lotfortynine.com/) +* [Many Folds Press](https://printingfortunes.info/) +* [Partners and Son](https://www.partnersandson.com/shop-1) +* [Pet Riso](https://www.instagram.com/pet_riso/?hl=en) +* [Risolve Studio](https://risolvestudio.com/) +* [Second State Press](https://www.secondstatepress.org/) +* [The Soapbox](https://www.phillysoapbox.org/) +* [Solita Zine](https://www.instagram.com/solitazine/?hl=en) + +There will be snacks, burgers, hot dogs, and vegan options. Plus specially designed toppings and beverages from the FORTUNE team.  Ulises deadstock will be available for 25%, 50% and 75% off! + +Free & open to the public! Raffle every hour! + +Please note: Food and drink will be served outdoors. Masks are requested while indoors. Icebox Project Space is ADA accessible. \ No newline at end of file diff --git a/_posts/2022-09-06-submit-your-book.md b/_posts/2022-09-06-submit-your-book.md new file mode 100644 index 0000000..2afa878 --- /dev/null +++ b/_posts/2022-09-06-submit-your-book.md @@ -0,0 +1,22 @@ +--- +title: Submit Your Book +date: 2019-11-12T18:59:54.285Z +layout: post +categories: right +published: true +--- +![](/assets/img/tothewholewideworld.jpg) + +Ulises is dedicated to artists’ books and independent art publications. We aim to support people who make books and expand the boundaries of what art publishing can be. If you have a publication that you would like Ulises to consider for our shop, please complete the **[Publication Review Form](https://formfacade.com/public/112249199778780145474/all/form/1FAIpQLSe1SAV81fyD0-95YBEViGFzc2j3Bo9deIDyjHSNJV4hPIYSVQ).** + +**Please Note:**  + +* Publications are handled on a consignment basis. +* The retail price is split,​ 60​% to the consignor and 40%​ to Ulises.  +* Ulises reviews submissions monthly.​​ +* We are only able to respond to publication submissions we intend to stock.  +* ​Submissions will need to include either digital examples or a physical copy​ +* ​If you are sending/dropping off a physical copy, you must still fill out the Review Form and your submission will only be considered once the publication is received. ​ +* Ulises does not offer pick-up or return service for submissions.​ +* Ulises will only consider for review books that have already been published or self-published. +* ​At the time of submission, a minimum of 50 copies of the title must have already been produced.​ \ No newline at end of file diff --git a/_posts/2022-09-16-see-you-at-the-nyabf.md b/_posts/2022-09-16-see-you-at-the-nyabf.md new file mode 100644 index 0000000..28a6cc0 --- /dev/null +++ b/_posts/2022-09-16-see-you-at-the-nyabf.md @@ -0,0 +1,13 @@ +--- +title: See you at the NYABF +date: 2022-09-16T15:42:32.386Z +event_date: October 13–16, 2022 +layout: post +categories: left +published: true +--- +![](/assets/img/pmabf22_instagram_1080_square.jpg) + +Printed Matter's NY Art Book Fair takes place Oct 13-16 at 548 W 22nd St. NY. Find Ulises at table **C42** and pick up a copy of Publishing As Practice! + +Note that this year some fair days are ticked/require advance registration. Sign up and learn more about the [NYABF here](https://nyabf2022.printedmatterartbookfairs.org/) \ No newline at end of file diff --git a/_posts/2022-10-03-boston-art-book-fair.md b/_posts/2022-10-03-boston-art-book-fair.md new file mode 100644 index 0000000..122270c --- /dev/null +++ b/_posts/2022-10-03-boston-art-book-fair.md @@ -0,0 +1,11 @@ +--- +title: Boston Art Book Fair +date: 2022-10-30T20:12:36.721Z +event_date: November 4-6, 2022 +layout: post +categories: left +published: true +--- +![](/assets/img/bosabf-mainsocialtilesave-the-date-80.jpeg) + +Ulises will be in Boston for the Boston Art Book Fair, November 4-6 at the Cyclorama at the Boston Center for the Arts. It's going to be wicked fun! Find out more [here](https://bostonartbookfair.com/). \ No newline at end of file diff --git a/_posts/2023-03-04-multiple-formats.md b/_posts/2023-03-04-multiple-formats.md new file mode 100644 index 0000000..7c6baa1 --- /dev/null +++ b/_posts/2023-03-04-multiple-formats.md @@ -0,0 +1,29 @@ +--- +title: Multiple Formats +date: 2023-03-04T17:34:46.201Z +event_date: March 16-18, 2023 +layout: post +categories: left +published: true +--- +![Mutliple Formats](/assets/img/screen-shot-2023-03-03-at-10.31.59-pm.png) + +[Multiple Formats: Contemporary Art Book Symposium](https://multipleformats.cargo.site/) weaves together conversations about artist books and higher education, pedagogical practices involving artist books, artist advocacy, and artist book distribution, collection, and access. Intended to be an elastic and inclusive forum for discussions about artist book publishing, Multiple Formats pays particular attention to publishing by graphic designers, the use and creation of artist books in visual arts programs, publishing as a personal and collaborative process, and other topics of interest. + +Keynote Lecture by Nontsikelelo Mutiti\ +Co-founder of Black Chalk & Co. and Director of Graduate Studies in Graphic Design at Yale University\ +March 16, 7:30 PM\ +\ +Art Book Symposium\ +March 17, 2023\ +11:00 AM to 6:00 PM\ +\ +Art Book Fair\ +March 18, 2023\ +11:00 AM to 6:00 PM\ +\ +All events are free + open to the public.\ +\ +Boston University, School of Visual Arts\ +808 Commonwealth Avenue\ +Boston, MA 02446 \ No newline at end of file diff --git a/_posts/2023-04-12-ulises-friends-school.md b/_posts/2023-04-12-ulises-friends-school.md new file mode 100644 index 0000000..7fcdda8 --- /dev/null +++ b/_posts/2023-04-12-ulises-friends-school.md @@ -0,0 +1,19 @@ +--- +title: Ulises Friends School +date: 2023-04-12T01:45:18.682Z +event_date: April 19-21, 2023 +layout: post +categories: left +published: true +--- +![](/assets/img/ups_fb_banner.jpeg) + +April 19-21, Ulises will be in Utrecht leading Ulises Friends School, a series of workshops that invite participants to investigate the generative potential of friendship. In simplest terms, Ulises is a bookshop and project space dedicated to artists' books and independent art publications. In the truest terms, Ulises is a collection of musings, longings, and assorted activities brought together by a group of friends. This is to say that friendship is the medium, ethos, and structure of Ulises. \ +\ +Ulises Friends School is a part of [Ultradependent Public School (UPS)](https://www.bakonline.org/program-item/full-program-ultradependent-public-schoool/) transforming BAK, basis voor actuele kunst, into a schoolhouse and a curriculum to learn what we really need to enact the worlds we really want.  Emphasizing study as a radically collective, public labor that lives in-between institutionalized hierarchies, UPS inhabits the edges between formal classrooms and everyday life.\ +\ +All participants will have the opportunity to be included in a cumulative publication, a “Yearbook\[let]” made over the three workshop periods.\ +\ +Day 1: “With Friends Like These…”\ +Day 2: “Truth be Told / You Didn’t Hear it From Me…”\ +Day 3: “Let’s Stay in Touch” \ No newline at end of file diff --git a/_posts/2023-06-15-big-summer-book-sale-2023.md b/_posts/2023-06-15-big-summer-book-sale-2023.md new file mode 100644 index 0000000..78b4536 --- /dev/null +++ b/_posts/2023-06-15-big-summer-book-sale-2023.md @@ -0,0 +1,23 @@ +--- +title: Big Summer Book Sale +date: 2023-06-15T00:38:43.719Z +event_date: Sunday, June 25, 2023 +layout: post +categories: left +published: true +--- +![](/assets/img/ulises-2023_production-files_02-02.jpg) + +It’s almost time for this year’s BIG SUMMER BOOK SALE hosted by Ulises, Icebox Project Space, and FORTUNE with the support of Penn Treaty Special Services District! + +On Sunday, June 25 from 11AM–5 PM at 1400 North American Ave all Ulises deadstock will be available for 25%, 50% and 75% off! Plus, there will be books, print, and all things adjacent from our friends: + +All Caps Studio, The Erotic Project,First Last,The Head & The Hand,Icebox Project Space, Iffy Books, Iota Editions, Logan DeCarme, Lot 49, Many Folds Press, Multiverse, Partners and Son, Pet Riso, Philadelphia Printworks, The Print Party, Risolve, Second State Press, Seen, The Soapbox, Solita Zine, Sometimes Publishing, Space 1026, Who Press’d Press + +Special guest RICE, tabling on behalf of the Save Chinatown Coalition + +Come for the wares, and stay for the snacks, drinks, and sweet summer vibes provided by the legendary Rashid Zakat. Free hotdogs until 3PM (w/ vegan options!) and specially designed beverages from the FORTUNE team + A RAFFLE EVERY HOUR! + +This event is free and open to the public. + +Flyer designed by [Nick Massarelli](https://nickmassarelli.com/). \ No newline at end of file diff --git a/_sass/_layouts.scss b/_sass/_layouts.scss new file mode 100644 index 0000000..fc22f6c --- /dev/null +++ b/_sass/_layouts.scss @@ -0,0 +1,938 @@ + + +// * * * * * Mixins & Globals * * * * * + +@mixin border { + border: 5px solid #0ff; +} + +@mixin transdefaults($params) { + transition: $params; + -webkit-transition: $params; + -moz-transition: $params; + -o-transition: $params; +} + +$col-padding: 4.5rem; + +.typeset p { + text-indent: 5rem; + -moz-hyphens: auto; + -webkit-hyphens: auto; + -o-hyphens: auto; + hyphens: auto; +} + +.typeset p.no-indent { + text-indent: 0; +} + +.typeset p img { + display: block; +} + +body { + overflow: hidden; +} + +.main-wrapper { + + @include outer-container(100%); + background-color: $backgroundColour; + + @include media-query($on-laptop){ + background-color: $backgroundColour; + position: relative; + } + + @include media-query($on-palm){ + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + overflow-x: hidden; + height: 100vh; + } +} + +.typeset p.left-justify { + text-indent: 0; +} + +// Perfect scrollbar overrides +// +// issue with typeset text-indent applying to images +// wrapped in

as parsed by markdown, forcing +// x scroll + +.ps#left { + + .ps__rail-y{ left: 0; } + .ps__rail-x{ display: none; } +} + +.ps#right { + + .ps__rail-y{ right: 0.2rem; } + .ps__rail-x{ display: none; } + +} + +// * * * * * End Mixins & Globals * * * * * + + +// * * * * * Basic Two Column Layout * * * * * + +// general post article/post + +.post-title h2 { + text-transform: uppercase; +} + +header.post-header p { + text-indent: 0; + text-align: center; +} + +article.post { + margin-bottom: 4rem; +} + +article.post div.post-content { + + & ul { + list-style: decimal; + } + + & ol li, & ul li { + + padding-top: .75rem; + text-indent: 0; + padding-left: .5rem; + } +} + +// General column content + +.column { + + @include span-columns(6); + background-color: $backgroundColour; + position: relative; + // top: -50vh; // hack for implementing splash panel + top: 0; + height: 100vh; + overflow-y: scroll; + overflow-x: hidden; + margin: 0; + padding: 0 $col-padding; + z-index: 2; + + h2 { text-align: center; } + + @include media-query($on-palm){ + @include outer-container(100%); + @include span-columns(12); + position: inherit; + height: auto; + } + + @media screen and (min-width: 480px) and (max-width: $on-palm) { + padding-top: 0; + padding-bottom: 0; + padding-left: 2 * $col-padding; + padding-right: 2 * $col-padding; + } + + @media screen and (max-width: 480px) { + padding: 0 1rem; + } +} + +.column#left { + + @include transdefaults(margin .5s ease-out 0s); + + /** styles for left column reverse color scheme **/ + + background-color: lighten($bodyColour, 25%); + color: $backgroundColour; + + .post-title h2, .site-title h4, a { + color: $backgroundColour; + } + + article { + & a, & a:hover, & a:hover, + & a:focus, & a:visited { + color: $backgroundColour; + background-image: none; + text-decoration: underline; + text-shadow: unset; + } + + & a:hover { + color: lighten($PasP-primary, 5%); + // color: $msFuschia; + } + } +} + +.column#left .mobile-only { + display: none; + @include media-query($on-palm) { + display: unset; + } +} + +.column#right { + float: right; + @include transdefaults(margin .5s ease-out 0s); +} + +// both column headers + +header.site-header { + + @include span-columns(12); + padding-top: 2rem; + margin-bottom: 2rem; + + .title-stack { + width: 100%; + display: flex; + justify-content: space-between; + } + + .info-wrapper { + display: flex; + flex-wrap: no-wrap; + justify-content: space-between; + @include fontsize(delta); + + p { + text-indent: unset; + margin: 0; + line-height: 2rem; + } + } + + .content-wrapper { + width: 100%; + } + + & a, & a:hover, & a:hover, + & a:focus, & a:visited { + color: $bodyColour; + background-image: none; + cursor: pointer; + text-decoration: none; + background-image: none; + text-shadow: unset; + } + + & a:hover { + color: $linkColour; + } + + & a span{ + font-family: unquote(map-get($bodytype, font-family)); + font-weight: 300; + } + + & p span { + font-family: unquote(map-get($headingtype, font-family)); + font-weight: 300; + } + + @include media-query($on-laptop) { + .typeset h4, .info-wrapper { + font-size: inherit; + } + + .info-wrapper { + width: 100%; + flex-direction: column; + align-items: center; + + p,span { + margin: 0 0 0 0; + text-align: center; + } + } + } + + a#instagram-link { + display: block; + width: 15rem; + margin: 1.5rem auto; + border: 2px solid $backgroundColour; + border-radius: 75%; + clear: both; + @include transdefaults(background-color .25s ease-out 0s); + } + + a#instagram-link span { + font-family: unquote(map-get($headingtype,font-family)); + color: $backgroundColour; + text-transform: uppercase; + max-width: 8rem; + padding: .5rem 0; + margin: 0 auto; + display: block; + @include transdefaults(color .1s linear 0s); + } + + a:hover#instagram-link, + a:visited#instagram-link { + color: unset; + } + + a:hover#instagram-link { + background-color: $backgroundColour; + span {color: $bodyColour;} + } +} + +// left column header + +header.site-header.left { + + display: flex; + justify-content: space-between; + flex-wrap: wrap; + min-height: 4rem; + padding-bottom: .3rem; + + a h4 { margin: 0; } + + #info-button p a:hover, a:hover p { + color: $PasP-primary; + } + + a#instagram-link { + border: 2px solid $bodyColour; + } + + a#instagram-link span { + color: $bodyColour; + } + + a:hover#instagram-link, + a:visited#instagram-link { + color: unset; + } + + a:hover#instagram-link { + background-color: $bodyColour; + span {color: $backgroundColour;} + } +} + +// right column header + +header.site-header.right { + + @include media-query($on-laptop) { + // margin-top: 9rem; + } + + #info-button { + // margin-left: 2em; + } +} + + +// column styles for PasP Reveal pane animation + +.column#left.reveal { + margin-left: -50%; + @include transdefaults(margin .5s ease-out 0s); +} + +.column#right.reveal { + margin-right: 50%; + @include transdefaults(margin .5s ease-out 0s); +} + +.column#left.reveal, +.column#right.reveal { + + @include media-query($on-palm){ + margin: 0 auto; + } +} + +#pasp .pasp-reveal { + @include media-query($on-palm) { + display: none; + } +} + +#pasp .pasp-reveal:hover { + .close-x { + stroke: $linkColour; + } +} + +.column.column--right .pasp-reveal { + visibility: hidden; + + @include media-query($on-palm) { + visibility: visible; + } +} + +#pasp-reveal { + + @include transdefaults(color .2s ease-out); + + z-index: 3; + cursor: pointer; + font-family: unquote(map-get($headingtype,font-family)); + line-height: 2.26rem; + + p { + display: inline-block; + @include fontsize(delta); + float: right; + } + + svg { + display: inline-block; + width: 4rem; + height: 4rem; + stroke: $bodyColour; + fill: transparent; + stroke-width: .75; + @include transdefaults(stroke .2s ease-out); + + position: relative; + top: 1rem; + right: -14rem; + } + + svg.hide, + &:hover svg.hide { + stroke: rgba(255,255,255,0); + } + + &:hover, &:hover svg { + color: $PasP-primary; + stroke: $PasP-primary; + // color: $msFuschia; + // stroke: $msFuschia; + } + + + @include media-query($on-palm) { + display: none; + } +} + +// added style to avoid white on yellow for Bidoun scheme +div#right.reveal + #pasp-reveal { + svg { + stroke: $PasP-primary; + } + + p { + color: $PasP-primary; + } + + &:hover { + + p { color: lighten($PasP-primary, 15%); } + svg { stroke: lighten($PasP-primary, 15%); } + } +} + +#pasp-reveal.fixed { + position: fixed; + right: $col-padding; + top: .8rem; +} + +.typeset#pasp { + + z-index: 1; + position: relative; + // top: -150vh; // hack for implementing splash panel + top: -100vh; + right: -50vw; + + article.post { + padding-top: 6.1rem; + } + + @include media-query($on-palm){ + display: none; + }; + +} + +#pasp { + + &.column, + article.post, + .slide .expanded { + + background-color: $PasP-contrast; + + h1,h2,h3,h4,p, ul { + color: $PasP-primary; + font-family: unquote(map-get($headingtype, font-family)); + font-style: normal; + font-weight: map-get($bodytype, regular); + } + + h3 { + line-height: 3rem; + } + + ul { + list-style: none; + } + + & a, & a:hover, & a:hover, + & a:focus, & a:visited { + color: $PasP-primary; + // color: $backgroundColour; + background-image: none; + cursor: pointer; + text-shadow: unset; + text-decoration: underline; + } + + & a:hover { + color: lighten($PasP-primary, 15%); + } + + img { + width: 200px + } + } +} + +// column vertical slide panels + +.slide { + + width: 50vw; + height: 0; + position: relative; + left: -$col-padding; + + color: $backgroundColour; + + @include media-query($on-palm){ + + min-width: 100vw; + left: -2 * $col-padding - 1rem; + padding: 0 1rem; + + & > p:last-child { padding-bottom: 1rem; } + } + + @media screen and (max-width: 480px){ + + min-width: 100vw; + left: -$col-padding/2 + .25rem; + padding: 0 1rem; + + & > p:last-child { padding-bottom: 1rem; } + } +} + +.slide .excerpted { + max-height: 0; + overflow: hidden; +} + +.slide .expanded { + + // margin-bottom: $col-padding/2; + max-height: 0; + padding: 0rem $col-padding; + overflow: hidden; + z-index: 99; + border-top: 2rem solid $backgroundColour; + // border-top: 2rem solid magenta; + + @include transdefaults(max-height 500ms linear); + + & > p { clear: both; } + + & > p:last-child { padding-bottom: $col-padding/2; } + + @media screen and (min-width: 480px) and (max-width: $on-palm) { + width: 98vw; + left: -2 * $col-padding; + } + + @include media-query($on-palm) { + + min-width: 100vw; + left: -1rem; + & > p:last-child { padding-bottom: 1rem; } + } + + @media screen and (max-width: 480px) { + padding: 0 1rem; + } +} + +.site-header.left .slide .expanded { + border-top: 2rem solid lighten($bodyColour, 25%); +} + +.slide .expanded.show { + + // height for expanded info panel + width: 100%; + max-height: 200rem; + padding: 0rem $col-padding; + + @media screen and (max-width: 480px) { + padding: 0 1rem; + } + + -webkit-box-shadow: 0 .75rem 6px -8px rgba(100,100,100,.75); + -moz-box-shadow: 0 .75rem 6px -8px rgba(100,100,100,.75); + box-shadow: 0 .75rem 6px -8px rgba(100,100,100,.75); +} + +// fudging offsets so both panels appear +// in the same spot on mobile + +#pasp .slide .expanded { + + & > p:first-child { margin-top: 2rem;} +} + +#info .slide .expanded { + + & > div.info-wrapper:nth-of-type(1) { margin-top: 1rem;} +} + +// individual panels in mobile + +#info .slide .expanded{ + + .info-wrapper p { + margin: 0; + } + + .info-wrapper:nth-child(2) { + margin-bottom: 3rem; + } + + background-color: lighten($bodyColour, 25%); + color: $backgroundColour; + + @include media-query($on-palm) { + + background-color: $backgroundColour; + color: $bodyColour; + } + + & .slide .info-wrapper p { + margin: 0; + } + + & .slide div.info-wrapper:nth-child(2) { + margin-bottom: 3rem; + } +} + +#info .slide .expanded { + + // mailchimp embed form + & div#mc_embed_signup { + + width: 75%; + float: left; + margin-left: 12.5%; + + label { display: none; } + + & div.mc-field-group, + & div.clear { + + display: inline; + float: left; + + } + + // mc input field + & div.mc-field-group { + + width: 90%; + margin-bottom: 1.55rem; + + & input { + width: 100%; + height: 2.75rem; + color: $backgroundColour; + border: 2px solid $backgroundColour; + padding-left: 1rem; + border-radius: 0; + } + + & input::placeholder { + font-family: unquote(map-get($headingtype, font-family)); + font-style: normal; + font-weight: map-get($bodytype, regular); + } + } + + // mc input button + & div.clear { width: 10%; float: right; } + & div.clear input.button { + + height: 2.75rem; + background-color: $backgroundColour; + color: $bodyColour; + font-size: 2rem; + padding: 0 0.3rem; + border: unset; + border-radius: 1px; + margin: 0; + } + + & div.clear input.button:hover { + color: $linkColour; + } + } +} + +// square buy now button + +h1.button#buy { + display: block; + margin: 1.5rem auto; + @include transdefaults(background-color .25s ease-out 0s); + max-width: 30rem; + background-image: none; + cursor: pointer; + background-image: none; + text-shadow: unset; + + border: 2px solid $bodyColour; + border-radius: 2rem; +} + +h1.button#buy a { + font-family: unquote(map-get($headingtype,font-family)); + color: $bodyColour; + text-transform: uppercase; + text-decoration: none; + margin: 0 auto; + padding: .5rem 1rem 1rem 1rem; + text-align: center; + display: block; + @include transdefaults(color .1s linear 0s); + +} + +h1.button#buy a:hover, +h1.button#buy a:visited{ + color: unset; + text-decoration: none; +} + +h1.button#buy:hover { + background-color: $bodyColour; + a {color: $backgroundColour;} +} + +.mobile-only h1.button#buy { + border: 2px solid $backgroundColour; + + a { color: $backgroundColour; } + + &:hover { + background-color: $backgroundColour; + a {color: $bodyColour;} + } +} + +// * * * * * Splash Page Elements * * * * * + +.splash-panel.hide { + top: -50vh; + height: 50vh; + @include transdefaults(all .5s ease-out .1s); + + a#splash-body-anchor div.residents { + top: -100vh; + @include transdefaults(top .5s ease-out .1s); + } + +} + +.splash-panel { + + @include transdefaults(height 1s ease-out); + background-color: lighten($bodyColour, 10%); + height: 100vh; + width: 100vw; + position: relative; + display: block; + top: 0; + z-index: 99; +} + +.splash-panel a { + + height: 100%; + display: block; + + span { + @include transdefaults(color .5s linear); + } + + div.residents { + position: absolute; + top: 5em; + right: 3em; + } + + p { + + position: relative; + line-height: 6rem; + letter-spacing: .8rem; + + font-family: Kadisoka; + text-transform: uppercase; + font-size: 5.75rem; + @include transdefaults(color .5s linear); + + @include media-query ($on-palm){ + display: none; + } + } + + p#hw { + + text-indent: 1em; + left: .4em; + } + + p#ms{ + text-indent: -1em; + left: .5em; + span { + font-family: unquote(map-get($headingtype, font-family)); + } + } + + p#bd { + left: -1.25em; + } + + div.scroll-wrapper { + position: absolute; + top: 0; + overflow-x: hidden; + overflow-y: auto; + width: 100vw; + height: 100%; + max-height: 100vh; + right: -25px; + } + + div.scroll-wrapper div { + + width: 20%; + max-width: 300px; + // margin-left: 2rem; + float: left; + + @include media-query ($on-palm){ + width: 33%; + margin-left: 0; + } + + span { + display: block; + font-family: unquote(map-get($headingtype,font-family)); + font-size: 1.5rem; + line-height: 1.5rem; + text-transform: uppercase; + + @include media-query ($on-palm){ + // font-size: 1.1rem; + // line-height: 1.rem; + } + + } + } + + div.scroll-wrapper div.col-2 { + margin-left: 3%; + + @include media-query($on-palm){ + margin-left: 10%; + } + + } +} + + +// splash scroll color schemes +.splash-panel { + a, p, .scroll-wrapper { + display: block; + } +} + +.splash-panel a { + + height: 100%; + max-height: 100%; + + @include transdefaults(background-color 2s linear); + + + &.default { + background-color: lighten($bodyColour, 10%); + span,p { + color: $backgroundColour; + } + } + + &.inverse { + background-color: $backgroundColour; + span,p { + color: $bodyColour; + } + } + + &.hw { + background-color: $backgroundColour; + span,p { + color: $hwBlue; + } + } + + &.ms { + background-color: lighten($msGreen, 5%); + span,p { + color: $bodyColour; + } + } + + &.ms2 { + background-color: lighten($bodyColour, 10%); + span,p { + color: $msFuschia; + } + } + + &.bd { + background-color: $bYellow; + span,p { + color: $backgroundColour; + } + } +} \ No newline at end of file diff --git a/_sass/neat/_neat-helpers.scss b/_sass/neat/_neat-helpers.scss new file mode 100644 index 0000000..2d6d808 --- /dev/null +++ b/_sass/neat/_neat-helpers.scss @@ -0,0 +1,11 @@ +// Mixins +@import "mixins/clearfix"; + +// Functions +@import "functions/private"; +@import "functions/new-breakpoint"; + +// Settings +@import "settings/grid"; +@import "settings/visual-grid"; +@import "settings/disable-warnings"; diff --git a/_sass/neat/_neat.scss b/_sass/neat/_neat.scss new file mode 100644 index 0000000..e172171 --- /dev/null +++ b/_sass/neat/_neat.scss @@ -0,0 +1,23 @@ +// Neat 1.8.0 +// http://neat.bourbon.io +// Copyright 2012-2015 thoughtbot, inc. +// MIT License + +// Helpers +@import "neat-helpers"; + +// Grid +@import "grid/private"; +@import "grid/box-sizing"; +@import "grid/omega"; +@import "grid/outer-container"; +@import "grid/span-columns"; +@import "grid/row"; +@import "grid/shift"; +@import "grid/pad"; +@import "grid/fill-parent"; +@import "grid/media"; +@import "grid/to-deprecate"; +@import "grid/visual-grid"; +@import "grid/display-context"; +@import "grid/direction-context"; diff --git a/_sass/neat/functions/_new-breakpoint.scss b/_sass/neat/functions/_new-breakpoint.scss new file mode 100644 index 0000000..41ab955 --- /dev/null +++ b/_sass/neat/functions/_new-breakpoint.scss @@ -0,0 +1,49 @@ +@charset "UTF-8"; + +/// Returns a media context (media query / grid context) that can be stored in a variable and passed to `media()` as a single-keyword argument. Media contexts defined using `new-breakpoint` are used by the visual grid, as long as they are defined before importing Neat. +/// +/// @param {List} $query +/// A list of media query features and values. Each `$feature` should have a corresponding `$value`. +/// +/// If there is only a single `$value` in `$query`, `$default-feature` is going to be used. +/// +/// The number of total columns in the grid can be set by passing `$columns` at the end of the list (overrides `$total-columns`). For a list of valid values for `$feature`, click [here](http://www.w3.org/TR/css3-mediaqueries/#media1). +/// +/// @param {Number (unitless)} $total-columns [$grid-columns] +/// - Number of columns to use in the new grid context. Can be set as a shorthand in the first parameter. +/// +/// @example scss - Usage +/// $mobile: new-breakpoint(max-width 480px 4); +/// +/// .element { +/// @include media($mobile) { +/// @include span-columns(4); +/// } +/// } +/// +/// @example css - CSS Output +/// @media screen and (max-width: 480px) { +/// .element { +/// display: block; +/// float: left; +/// margin-right: 7.42297%; +/// width: 100%; +/// } +/// .element:last-child { +/// margin-right: 0; +/// } +/// } + +@function new-breakpoint($query: $feature $value $columns, $total-columns: $grid-columns) { + @if length($query) == 1 { + $query: $default-feature nth($query, 1) $total-columns; + } @else if is-even(length($query)) { + $query: append($query, $total-columns); + } + + @if is-not(belongs-to($query, $visual-grid-breakpoints)) { + $visual-grid-breakpoints: append($visual-grid-breakpoints, $query, comma) !global; + } + + @return $query; +} diff --git a/_sass/neat/functions/_private.scss b/_sass/neat/functions/_private.scss new file mode 100644 index 0000000..872d4dc --- /dev/null +++ b/_sass/neat/functions/_private.scss @@ -0,0 +1,114 @@ +// Not function for Libsass compatibility +// https://github.com/sass/libsass/issues/368 +@function is-not($value) { + @return if($value, false, true); +} + +// Checks if a number is even +@function is-even($int) { + @return $int % 2 == 0; +} + +// Checks if an element belongs to a list or not +@function belongs-to($tested-item, $list) { + @return is-not(not-belongs-to($tested-item, $list)); +} + +@function not-belongs-to($tested-item, $list) { + @return is-not(index($list, $tested-item)); +} + +// Contains display value +@function contains-display-value($query) { + @return belongs-to(table, $query) + or belongs-to(block, $query) + or belongs-to(inline-block, $query) + or belongs-to(inline, $query); +} + +// Parses the first argument of span-columns() +@function container-span($span: $span) { + @if length($span) == 3 { + $container-columns: nth($span, 3); + @return $container-columns; + } @else if length($span) == 2 { + $container-columns: nth($span, 2); + @return $container-columns; + } + + @return $grid-columns; +} + +@function container-shift($shift: $shift) { + $parent-columns: $grid-columns !default !global; + + @if length($shift) == 3 { + $container-columns: nth($shift, 3); + @return $container-columns; + } @else if length($shift) == 2 { + $container-columns: nth($shift, 2); + @return $container-columns; + } + + @return $parent-columns; +} + +// Generates a striped background +@function gradient-stops($grid-columns, $color: $visual-grid-color) { + $transparent: transparent; + + $column-width: flex-grid(1, $grid-columns); + $gutter-width: flex-gutter($grid-columns); + $column-offset: $column-width; + + $values: ($transparent 0, $color 0); + + @for $i from 1 to $grid-columns*2 { + @if is-even($i) { + $values: append($values, $transparent $column-offset, comma); + $values: append($values, $color $column-offset, comma); + $column-offset: $column-offset + $column-width; + } @else { + $values: append($values, $color $column-offset, comma); + $values: append($values, $transparent $column-offset, comma); + $column-offset: $column-offset + $gutter-width; + } + } + + @return $values; +} + +// Layout direction +@function get-direction($layout, $default) { + $direction: null; + + @if to-upper-case($layout) == "LTR" or to-upper-case($layout) == "RTL" { + $direction: direction-from-layout($layout); + } @else { + $direction: direction-from-layout($default); + } + + @return $direction; +} + +@function direction-from-layout($layout) { + $direction: null; + + @if to-upper-case($layout) == "LTR" { + $direction: right; + } @else { + $direction: left; + } + + @return $direction; +} + +@function get-opposite-direction($direction) { + $opposite-direction: left; + + @if $direction == "left" { + $opposite-direction: right; + } + + @return $opposite-direction; +} diff --git a/_sass/neat/grid/_box-sizing.scss b/_sass/neat/grid/_box-sizing.scss new file mode 100644 index 0000000..b6d3fec --- /dev/null +++ b/_sass/neat/grid/_box-sizing.scss @@ -0,0 +1,15 @@ +@charset "UTF-8"; + +@if $border-box-sizing == true { + html { // http://bit.ly/1qk2tVR + box-sizing: border-box; + } + + * { + &, + &::after, + &::before { + box-sizing: inherit; + } + } +} diff --git a/_sass/neat/grid/_direction-context.scss b/_sass/neat/grid/_direction-context.scss new file mode 100644 index 0000000..7b0d46e --- /dev/null +++ b/_sass/neat/grid/_direction-context.scss @@ -0,0 +1,33 @@ +@charset "UTF-8"; + +/// Changes the direction property used by other mixins called in the code block argument. +/// +/// @param {String} $direction [left-to-right] +/// Layout direction to be used within the block. Can be `left-to-right` or `right-to-left`. +/// +/// @example scss - Usage +/// @include direction-context(right-to-left) { +/// .right-to-left-block { +/// @include span-columns(6); +/// } +/// } +/// +/// @example css - CSS Output +/// .right-to-left-block { +/// float: right; +/// ... +/// } + +@mixin direction-context($direction: left-to-right) { + $scope-direction: $layout-direction; + + @if to-lower-case($direction) == "left-to-right" { + $layout-direction: LTR !global; + } @else if to-lower-case($direction) == "right-to-left" { + $layout-direction: RTL !global; + } + + @content; + + $layout-direction: $scope-direction !global; +} diff --git a/_sass/neat/grid/_display-context.scss b/_sass/neat/grid/_display-context.scss new file mode 100644 index 0000000..ed9b063 --- /dev/null +++ b/_sass/neat/grid/_display-context.scss @@ -0,0 +1,28 @@ +@charset "UTF-8"; + +/// Changes the display property used by other mixins called in the code block argument. +/// +/// @param {String} $display [block] +/// Display value to be used within the block. Can be `table` or `block`. +/// +/// @example scss +/// @include display-context(table) { +/// .display-table { +/// @include span-columns(6); +/// } +/// } +/// +/// @example css +/// .display-table { +/// display: table-cell; +/// ... +/// } + +@mixin display-context($display: block) { + $scope-display: $container-display-table; + $container-display-table: $display == table !global; + + @content; + + $container-display-table: $scope-display !global; +} diff --git a/_sass/neat/grid/_fill-parent.scss b/_sass/neat/grid/_fill-parent.scss new file mode 100644 index 0000000..415f0b1 --- /dev/null +++ b/_sass/neat/grid/_fill-parent.scss @@ -0,0 +1,22 @@ +@charset "UTF-8"; + +/// Forces the element to fill its parent container. +/// +/// @example scss - Usage +/// .element { +/// @include fill-parent; +/// } +/// +/// @example css - CSS Output +/// .element { +/// width: 100%; +/// box-sizing: border-box; +/// } + +@mixin fill-parent() { + width: 100%; + + @if $border-box-sizing == false { + box-sizing: border-box; + } +} diff --git a/_sass/neat/grid/_media.scss b/_sass/neat/grid/_media.scss new file mode 100644 index 0000000..bd516e9 --- /dev/null +++ b/_sass/neat/grid/_media.scss @@ -0,0 +1,92 @@ +@charset "UTF-8"; + +/// Outputs a media-query block with an optional grid context (the total number of columns used in the grid). +/// +/// @param {List} $query +/// A list of media query features and values, where each `$feature` should have a corresponding `$value`. +/// For a list of valid values for `$feature`, click [here](http://www.w3.org/TR/css3-mediaqueries/#media1). +/// +/// If there is only a single `$value` in `$query`, `$default-feature` is going to be used. +/// +/// The number of total columns in the grid can be set by passing `$columns` at the end of the list (overrides `$total-columns`). +/// +/// +/// @param {Number (unitless)} $total-columns [$grid-columns] +/// - Number of columns to use in the new grid context. Can be set as a shorthand in the first parameter. +/// +/// @example scss - Usage +/// .responsive-element { +/// @include media(769px) { +/// @include span-columns(6); +/// } +/// } +/// +/// .new-context-element { +/// @include media(min-width 320px max-width 480px, 6) { +/// @include span-columns(6); +/// } +/// } +/// +/// @example css - CSS Output +/// @media screen and (min-width: 769px) { +/// .responsive-element { +/// display: block; +/// float: left; +/// margin-right: 2.35765%; +/// width: 48.82117%; +/// } +/// +/// .responsive-element:last-child { +/// margin-right: 0; +/// } +/// } +/// +/// @media screen and (min-width: 320px) and (max-width: 480px) { +/// .new-context-element { +/// display: block; +/// float: left; +/// margin-right: 4.82916%; +/// width: 100%; +/// } +/// +/// .new-context-element:last-child { +/// margin-right: 0; +/// } +/// } + +@mixin media($query: $feature $value $columns, $total-columns: $grid-columns) { + @if length($query) == 1 { + @media screen and ($default-feature: nth($query, 1)) { + $default-grid-columns: $grid-columns; + $grid-columns: $total-columns !global; + @content; + $grid-columns: $default-grid-columns !global; + } + } @else { + $loop-to: length($query); + $media-query: "screen and "; + $default-grid-columns: $grid-columns; + $grid-columns: $total-columns !global; + + @if is-not(is-even(length($query))) { + $grid-columns: nth($query, $loop-to) !global; + $loop-to: $loop-to - 1; + } + + $i: 1; + @while $i <= $loop-to { + $media-query: $media-query + "(" + nth($query, $i) + ": " + nth($query, $i + 1) + ") "; + + @if ($i + 1) != $loop-to { + $media-query: $media-query + "and "; + } + + $i: $i + 2; + } + + @media #{$media-query} { + @content; + $grid-columns: $default-grid-columns !global; + } + } +} diff --git a/_sass/neat/grid/_omega.scss b/_sass/neat/grid/_omega.scss new file mode 100644 index 0000000..80f918a --- /dev/null +++ b/_sass/neat/grid/_omega.scss @@ -0,0 +1,87 @@ +@charset "UTF-8"; + +/// Removes the element's gutter margin, regardless of its position in the grid hierarchy or display property. It can target a specific element, or every `nth-child` occurrence. Works only with `block` layouts. +/// +/// @param {List} $query [block] +/// List of arguments. Supported arguments are `nth-child` selectors (targets a specific pseudo element) and `auto` (targets `last-child`). +/// +/// When passed an `nth-child` argument of type `*n` with `block` display, the omega mixin automatically adds a clear to the `*n+1` th element. Note that composite arguments such as `2n+1` do not support this feature. +/// +/// **Deprecation warning**: The omega mixin will no longer take a `$direction` argument. To change the layout direction, use `row($direction)` or set `$default-layout-direction` instead. +/// +/// @example scss - Usage +/// .element { +/// @include omega; +/// } +/// +/// .nth-element { +/// @include omega(4n); +/// } +/// +/// @example css - CSS Output +/// .element { +/// margin-right: 0; +/// } +/// +/// .nth-element:nth-child(4n) { +/// margin-right: 0; +/// } +/// +/// .nth-element:nth-child(4n+1) { +/// clear: left; +/// } + +@mixin omega($query: block, $direction: default) { + $table: belongs-to(table, $query); + $auto: belongs-to(auto, $query); + + @if $direction != default { + @include -neat-warn("The omega mixin will no longer take a $direction argument. To change the layout direction, use the direction(){...} mixin."); + } @else { + $direction: get-direction($layout-direction, $default-layout-direction); + } + + @if $table { + @include -neat-warn("The omega mixin no longer removes padding in table layouts."); + } + + @if length($query) == 1 { + @if $auto { + &:last-child { + margin-#{$direction}: 0; + } + } + + @else if contains-display-value($query) and $table == false { + margin-#{$direction}: 0; + } + + @else { + @include nth-child($query, $direction); + } + } @else if length($query) == 2 { + @if $auto { + &:last-child { + margin-#{$direction}: 0; + } + } @else { + @include nth-child(nth($query, 1), $direction); + } + } @else { + @include -neat-warn("Too many arguments passed to the omega() mixin."); + } +} + +@mixin nth-child($query, $direction) { + $opposite-direction: get-opposite-direction($direction); + + &:nth-child(#{$query}) { + margin-#{$direction}: 0; + } + + @if type-of($query) == number and unit($query) == "n" { + &:nth-child(#{$query}+1) { + clear: $opposite-direction; + } + } +} diff --git a/_sass/neat/grid/_outer-container.scss b/_sass/neat/grid/_outer-container.scss new file mode 100644 index 0000000..d3f6267 --- /dev/null +++ b/_sass/neat/grid/_outer-container.scss @@ -0,0 +1,34 @@ +@charset "UTF-8"; + +/// Makes an element a outer container by centering it in the viewport, clearing its floats, and setting its `max-width`. +/// Although optional, using `outer-container` is recommended. The mixin can be called on more than one element per page, as long as they are not nested. +/// +/// @param {Number [unit]} $local-max-width [$max-width] +/// Max width to be applied to the element. Can be a percentage or a measure. +/// +/// @example scss - Usage +/// .element { +/// @include outer-container(100%); +/// } +/// +/// @example css - CSS Output +/// .element { +/// max-width: 100%; +/// margin-left: auto; +/// margin-right: auto; +/// } +/// +/// .element::after { +/// clear: both; +/// content: ""; +/// display: table; +/// } + +@mixin outer-container($local-max-width: $max-width) { + @include clearfix; + max-width: $local-max-width; + margin: { + left: auto; + right: auto; + } +} diff --git a/_sass/neat/grid/_pad.scss b/_sass/neat/grid/_pad.scss new file mode 100644 index 0000000..d697e1b --- /dev/null +++ b/_sass/neat/grid/_pad.scss @@ -0,0 +1,25 @@ +@charset "UTF-8"; + +/// Adds padding to the element. +/// +/// @param {List} $padding [flex-gutter()] +/// A list of padding value(s) to use. Passing `default` in the list will result in using the gutter width as a padding value. +/// +/// @example scss - Usage +/// .element { +/// @include pad(30px -20px 10px default); +/// } +/// +/// @example css - CSS Output +/// .element { +/// padding: 30px -20px 10px 2.35765%; +/// } + +@mixin pad($padding: flex-gutter()) { + $padding-list: null; + @each $value in $padding { + $value: if($value == 'default', flex-gutter(), $value); + $padding-list: join($padding-list, $value); + } + padding: $padding-list; +} diff --git a/_sass/neat/grid/_private.scss b/_sass/neat/grid/_private.scss new file mode 100644 index 0000000..4c4e18c --- /dev/null +++ b/_sass/neat/grid/_private.scss @@ -0,0 +1,35 @@ +$parent-columns: $grid-columns !default; +$fg-column: $column; +$fg-gutter: $gutter; +$fg-max-columns: $grid-columns; +$container-display-table: false !default; +$layout-direction: LTR !default; + +@function flex-grid($columns, $container-columns: $fg-max-columns) { + $width: $columns * $fg-column + ($columns - 1) * $fg-gutter; + $container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter; + @return percentage($width / $container-width); +} + +@function flex-gutter($container-columns: $fg-max-columns, $gutter: $fg-gutter) { + $container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter; + @return percentage($gutter / $container-width); +} + +@function grid-width($n) { + @return $n * $gw-column + ($n - 1) * $gw-gutter; +} + +@function get-parent-columns($columns) { + @if $columns != $grid-columns { + $parent-columns: $columns !global; + } @else { + $parent-columns: $grid-columns !global; + } + + @return $parent-columns; +} + +@function is-display-table($container-is-display-table, $display) { + @return $container-is-display-table == true or $display == table; +} diff --git a/_sass/neat/grid/_row.scss b/_sass/neat/grid/_row.scss new file mode 100644 index 0000000..4d913a9 --- /dev/null +++ b/_sass/neat/grid/_row.scss @@ -0,0 +1,52 @@ +@charset "UTF-8"; + +/// Designates the element as a row of columns in the grid layout. It clears the floats on the element and sets its display property. Rows can't be nested, but there can be more than one row element—with different display properties—per layout. +/// +/// @param {String} $display [default] +/// Sets the display property of the element and the display context that will be used by its children. Can be `block` or `table`. +/// +/// @param {String} $direction [$default-layout-direction] +/// Sets the layout direction. Can be `LTR` (left-to-right) or `RTL` (right-to-left). +/// +/// @example scss - Usage +/// .element { +/// @include row(); +/// } +/// +/// @example css - CSS Output +/// .element { +/// *zoom: 1; +/// display: block; +/// } +/// +/// .element:before, .element:after { +/// content: " "; +/// display: table; +/// } +/// +/// .element:after { +/// clear: both; +/// } + +@mixin row($display: default, $direction: $default-layout-direction) { + @if $direction != $default-layout-direction { + @include -neat-warn("The $direction argument will be deprecated in future versions in favor of the direction(){...} mixin."); + } + + $layout-direction: $direction !global; + + @if $display != default { + @include -neat-warn("The $display argument will be deprecated in future versions in favor of the display(){...} mixin."); + } + + @if $display == table { + display: table; + @include fill-parent; + table-layout: fixed; + $container-display-table: true !global; + } @else { + @include clearfix; + display: block; + $container-display-table: false !global; + } +} diff --git a/_sass/neat/grid/_shift.scss b/_sass/neat/grid/_shift.scss new file mode 100644 index 0000000..c0f24cd --- /dev/null +++ b/_sass/neat/grid/_shift.scss @@ -0,0 +1,50 @@ +@charset "UTF-8"; + +/// Translates an element horizontally by a number of columns. Positive arguments shift the element to the active layout direction, while negative ones shift it to the opposite direction. +/// +/// @param {Number (unitless)} $n-columns [1] +/// Number of columns by which the element shifts. +/// +/// @example scss - Usage +/// .element { +/// @include shift(-3); +/// } +/// +/// @example css - CSS output +/// .element { +/// margin-left: -25.58941%; +/// } + +@mixin shift($n-columns: 1) { + @include shift-in-context($n-columns); +} + +/// Translates an element horizontally by a number of columns, in a specific nesting context. +/// +/// @param {List} $shift +/// A list containing the number of columns to shift (`$columns`) and the number of columns of the parent element (`$container-columns`). +/// +/// The two values can be separated with any string such as `of`, `/`, etc. +/// +/// @example scss - Usage +/// .element { +/// @include shift(-3 of 6); +/// } +/// +/// @example css - CSS output +/// .element { +/// margin-left: -52.41458%; +/// } + +@mixin shift-in-context($shift: $columns of $container-columns) { + $n-columns: nth($shift, 1); + $parent-columns: container-shift($shift) !global; + + $direction: get-direction($layout-direction, $default-layout-direction); + $opposite-direction: get-opposite-direction($direction); + + margin-#{$opposite-direction}: $n-columns * flex-grid(1, $parent-columns) + $n-columns * flex-gutter($parent-columns); + + // Reset nesting context + $parent-columns: $grid-columns !global; +} diff --git a/_sass/neat/grid/_span-columns.scss b/_sass/neat/grid/_span-columns.scss new file mode 100644 index 0000000..a7f9b00 --- /dev/null +++ b/_sass/neat/grid/_span-columns.scss @@ -0,0 +1,94 @@ +@charset "UTF-8"; + +/// Specifies the number of columns an element should span. If the selector is nested the number of columns of its parent element should be passed as an argument as well. +/// +/// @param {List} $span +/// A list containing `$columns`, the unitless number of columns the element spans (required), and `$container-columns`, the number of columns the parent element spans (optional). +/// +/// If only one value is passed, it is assumed that it's `$columns` and that that `$container-columns` is equal to `$grid-columns`, the total number of columns in the grid. +/// +/// The values can be separated with any string such as `of`, `/`, etc. +/// +/// `$columns` also accepts decimals for when it's necessary to break out of the standard grid. E.g. Passing `2.4` in a standard 12 column grid will divide the row into 5 columns. +/// +/// @param {String} $display [block] +/// Sets the display property of the element. By default it sets the display property of the element to `block`. +/// +/// If passed `block-collapse`, it also removes the margin gutter by adding it to the element width. +/// +/// If passed `table`, it sets the display property to `table-cell` and calculates the width of the element without taking gutters into consideration. The result does not align with the block-based grid. +/// +/// @example scss - Usage +/// .element { +/// @include span-columns(6); +/// +/// .nested-element { +/// @include span-columns(2 of 6); +/// } +/// } +/// +/// @example css - CSS Output +/// .element { +/// display: block; +/// float: left; +/// margin-right: 2.35765%; +/// width: 48.82117%; +/// } +/// +/// .element:last-child { +/// margin-right: 0; +/// } +/// +/// .element .nested-element { +/// display: block; +/// float: left; +/// margin-right: 4.82916%; +/// width: 30.11389%; +/// } +/// +/// .element .nested-element:last-child { +/// margin-right: 0; +/// } + +@mixin span-columns($span: $columns of $container-columns, $display: block) { + $columns: nth($span, 1); + $container-columns: container-span($span); + + $parent-columns: get-parent-columns($container-columns) !global; + + $direction: get-direction($layout-direction, $default-layout-direction); + $opposite-direction: get-opposite-direction($direction); + + $display-table: is-display-table($container-display-table, $display); + + @if $display-table { + display: table-cell; + width: percentage($columns / $container-columns); + } @else { + float: #{$opposite-direction}; + + @if $display != no-display { + display: block; + } + + @if $display == collapse { + @include -neat-warn("The 'collapse' argument will be deprecated. Use 'block-collapse' instead."); + } + + @if $display == collapse or $display == block-collapse { + width: flex-grid($columns, $container-columns) + flex-gutter($container-columns); + + &:last-child { + width: flex-grid($columns, $container-columns); + } + + } @else { + margin-#{$direction}: flex-gutter($container-columns); + width: flex-grid($columns, $container-columns); + + &:last-child { + margin-#{$direction}: 0; + } + } + } +} diff --git a/_sass/neat/grid/_to-deprecate.scss b/_sass/neat/grid/_to-deprecate.scss new file mode 100644 index 0000000..aeea079 --- /dev/null +++ b/_sass/neat/grid/_to-deprecate.scss @@ -0,0 +1,97 @@ +@charset "UTF-8"; + +@mixin breakpoint($query:$feature $value $columns, $total-columns: $grid-columns) { + @include -neat-warn("The breakpoint() mixin was renamed to media() in Neat 1.0. Please update your project with the new syntax before the next version bump."); + + @if length($query) == 1 { + @media screen and ($default-feature: nth($query, 1)) { + $default-grid-columns: $grid-columns; + $grid-columns: $total-columns; + @content; + $grid-columns: $default-grid-columns; + } + } @else if length($query) == 2 { + @media screen and (nth($query, 1): nth($query, 2)) { + $default-grid-columns: $grid-columns; + $grid-columns: $total-columns; + @content; + $grid-columns: $default-grid-columns; + } + } @else if length($query) == 3 { + @media screen and (nth($query, 1): nth($query, 2)) { + $default-grid-columns: $grid-columns; + $grid-columns: nth($query, 3); + @content; + $grid-columns: $default-grid-columns; + } + } @else if length($query) == 4 { + @media screen and (nth($query, 1): nth($query, 2)) and (nth($query, 3): nth($query, 4)) { + $default-grid-columns: $grid-columns; + $grid-columns: $total-columns; + @content; + $grid-columns: $default-grid-columns; + } + } @else if length($query) == 5 { + @media screen and (nth($query, 1): nth($query, 2)) and (nth($query, 3): nth($query, 4)) { + $default-grid-columns: $grid-columns; + $grid-columns: nth($query, 5); + @content; + $grid-columns: $default-grid-columns; + } + } @else { + @include -neat-warn("Wrong number of arguments for breakpoint(). Read the documentation for more details."); + } +} + +@mixin nth-omega($nth, $display: block, $direction: default) { + @include -neat-warn("The nth-omega() mixin is deprecated. Please use omega() instead."); + @include omega($nth $display, $direction); +} + +/// Resets the active display property to `block`. Particularly useful when changing the display property in a single row. +/// +/// @example scss - Usage +/// .element { +/// @include row(table); +/// // Context changed to table display +/// } +/// +/// @include reset-display; +/// // Context is reset to block display + +@mixin reset-display { + $container-display-table: false !global; + @include -neat-warn("Resetting $display will be deprecated in future versions in favor of the display(){...} mixin."); +} + +/// Resets the active layout direction to the default value set in `$default-layout-direction`. Particularly useful when changing the layout direction in a single row. +/// +/// @example scss - Usage +/// .element { +/// @include row($direction: RTL); +/// // Context changed to right-to-left +/// } +/// +/// @include reset-layout-direction; +/// // Context is reset to left-to-right + +@mixin reset-layout-direction { + $layout-direction: $default-layout-direction !global; + @include -neat-warn("Resetting $direction will be deprecated in future versions in favor of the direction(){...} mixin."); +} + +/// Resets both the active layout direction and the active display property. +/// +/// @example scss - Usage +/// .element { +/// @include row(table, RTL); +/// // Context changed to table table and right-to-left +/// } +/// +/// @include reset-all; +/// // Context is reset to block display and left-to-right + +@mixin reset-all { + @include reset-display; + @include reset-layout-direction; +} diff --git a/_sass/neat/grid/_visual-grid.scss b/_sass/neat/grid/_visual-grid.scss new file mode 100644 index 0000000..1192d82 --- /dev/null +++ b/_sass/neat/grid/_visual-grid.scss @@ -0,0 +1,42 @@ +@charset "UTF-8"; + +@mixin grid-column-gradient($values...) { + background-image: -webkit-linear-gradient(left, $values); + background-image: -moz-linear-gradient(left, $values); + background-image: -ms-linear-gradient(left, $values); + background-image: -o-linear-gradient(left, $values); + background-image: unquote("linear-gradient(to left, #{$values})"); +} + +@if $visual-grid == true or $visual-grid == yes { + body:before { + @include grid-column-gradient(gradient-stops($grid-columns)); + content: ""; + display: inline-block; + height: 100%; + left: 0; + margin: 0 auto; + max-width: $max-width; + opacity: $visual-grid-opacity; + pointer-events: none; + position: fixed; + right: 0; + width: 100%; + + @if $visual-grid-index == back { + z-index: -1; + } + + @else if $visual-grid-index == front { + z-index: 9999; + } + + @each $breakpoint in $visual-grid-breakpoints { + @if $breakpoint { + @include media($breakpoint) { + @include grid-column-gradient(gradient-stops($grid-columns)); + } + } + } + } +} diff --git a/_sass/neat/mixins/_clearfix.scss b/_sass/neat/mixins/_clearfix.scss new file mode 100644 index 0000000..e68efc4 --- /dev/null +++ b/_sass/neat/mixins/_clearfix.scss @@ -0,0 +1,25 @@ +@charset "UTF-8"; + +/// Provides an easy way to include a clearfix for containing floats. +/// +/// @link http://goo.gl/yP5hiZ +/// +/// @example scss +/// .element { +/// @include clearfix; +/// } +/// +/// @example css +/// .element::after { +/// clear: both; +/// content: ""; +/// display: block; +/// } + +@mixin clearfix { + &::after { + clear: both; + content: ""; + display: block; + } +} diff --git a/_sass/neat/settings/_disable-warnings.scss b/_sass/neat/settings/_disable-warnings.scss new file mode 100644 index 0000000..3f9b92a --- /dev/null +++ b/_sass/neat/settings/_disable-warnings.scss @@ -0,0 +1,13 @@ +@charset "UTF-8"; + +/// Disable all deprecation warnings. Defaults to `false`. Set with a `!global` flag. +/// +/// @type Bool + +$disable-warnings: false !default; + +@mixin -neat-warn($message) { + @if $disable-warnings == false { + @warn "#{$message}"; + } +} diff --git a/_sass/neat/settings/_grid.scss b/_sass/neat/settings/_grid.scss new file mode 100644 index 0000000..ea2867c --- /dev/null +++ b/_sass/neat/settings/_grid.scss @@ -0,0 +1,51 @@ +@charset "UTF-8"; + +/// Sets the relative width of a single grid column. The unit used should be the same one used to define `$gutter`. Set with a `!global` flag. +/// +/// @type Number (Unit) + +$column: 4.2358em !default; + +/// Sets the relative width of a single grid gutter. The unit used should be the same one used to define `$column`. Set with the `!global` flag. +/// +/// @type Number (Unit) + +$gutter: 0em !default; + +/// Sets the total number of columns in the grid. Its value can be overridden inside a media query using the `media()` mixin. Set with the `!global` flag. +/// +/// @type Number (Unitless) + +$grid-columns: 12 !default; + +/// Sets the max-width property of the element that includes `outer-container()`. Set with the `!global` flag. +/// +/// @type Number (Unit) +/// +$max-width: 1200px !default; + +/// When set to true, it sets the box-sizing property of all elements to `border-box`. Set with a `!global` flag. +/// +/// @type Bool +/// +/// @example css - CSS Output +/// html { +/// box-sizing: border-box; } +/// +/// *, *::after, *::before { +/// box-sizing: inherit; +/// } + +$border-box-sizing: true !default; + +/// Sets the default [media feature](http://www.w3.org/TR/css3-mediaqueries/#media) that `media()` and `new-breakpoint()` revert to when only a breakpoint value is passed. Set with a `!global` flag. +/// +/// @type String + +$default-feature: min-width; // Default @media feature for the breakpoint() mixin + +///Sets the default layout direction of the grid. Can be `LTR` or `RTL`. Set with a `!global` flag. +/// +///@type String + +$default-layout-direction: LTR !default; diff --git a/_sass/neat/settings/_visual-grid.scss b/_sass/neat/settings/_visual-grid.scss new file mode 100644 index 0000000..9cd1815 --- /dev/null +++ b/_sass/neat/settings/_visual-grid.scss @@ -0,0 +1,27 @@ +@charset "UTF-8"; + +/// Displays the visual grid when set to true. The overlaid grid may be few pixels off depending on the browser's rendering engine and pixel rounding algorithm. Set with the `!global` flag. +/// +/// @type Bool + +$visual-grid: false !default; + +/// Sets the visual grid color. Set with `!global` flag. +/// +/// @type Color + +$visual-grid-color: #eee !default; + +/// Sets the `z-index` property of the visual grid. Can be `back` (behind content) or `front` (in front of content). Set with `!global` flag. +/// +/// @type String + +$visual-grid-index: back !default; + +/// Sets the opacity property of the visual grid. Set with `!global` flag. +/// +/// @type Number (unitless) + +$visual-grid-opacity: 0.4 !default; + +$visual-grid-breakpoints: () !default; diff --git a/_sass/perfect-scrollbar/_mixins.scss b/_sass/perfect-scrollbar/_mixins.scss new file mode 100644 index 0000000..5332ef2 --- /dev/null +++ b/_sass/perfect-scrollbar/_mixins.scss @@ -0,0 +1,128 @@ +@mixin scrollbar-rail-default($theme) { + display: none; + position: absolute; /* please don't change 'position' */ + opacity: map_get($theme, rail-default-opacity); + transition: background-color .2s linear, opacity .2s linear; +} + +@mixin scrollbar-rail-hover($theme) { + background-color: map_get($theme, rail-hover-bg); + opacity: map_get($theme, rail-hover-opacity); +} + +@mixin scrollbar-default($theme) { + position: absolute; /* please don't change 'position' */ + background-color: map_get($theme, bar-container-hover-bg); + border-radius: map_get($theme, border-radius); + transition: background-color .2s linear, height .2s linear, width .2s ease-in-out, + border-radius .2s ease-in-out; +} + +@mixin scrollbar-hover($theme) { + background-color: map_get($theme, bar-hover-bg); +} + +@mixin in-scrolling($theme) { + &.ps--in-scrolling { + &.ps--x > .ps__scrollbar-x-rail { + @include scrollbar-rail-hover($theme); + > .ps__scrollbar-x { + @include scrollbar-hover($theme); + height: map_get($theme, scrollbar-x-hover-height); + } + } + &.ps--y > .ps__scrollbar-y-rail { + @include scrollbar-rail-hover($theme); + > .ps__scrollbar-y { + @include scrollbar-hover($theme); + width: map_get($theme, scrollbar-y-hover-width); + } + } + } +} + +// Layout and theme mixin +@mixin ps-container($theme) { + -ms-touch-action: auto; + touch-action: auto; + overflow: hidden !important; + -ms-overflow-style: none; + + // Edge + @supports (-ms-overflow-style: none) { + overflow: auto !important; + } + // IE10+ + @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + overflow: auto !important; + } + + &.ps--active-x > .ps__scrollbar-x-rail, + &.ps--active-y > .ps__scrollbar-y-rail { + display: block; + background-color: map_get($theme, bar-bg); + } + + @include in-scrolling($theme); + + > .ps__scrollbar-x-rail { + @include scrollbar-rail-default($theme); + bottom: map_get($theme, scrollbar-x-rail-bottom); /* there must be 'bottom' for ps__scrollbar-x-rail */ + height: map_get($theme, scrollbar-x-rail-height); + + > .ps__scrollbar-x { + @include scrollbar-default($theme); + bottom: map_get($theme, scrollbar-x-bottom); /* there must be 'bottom' for ps__scrollbar-x */ + height: map_get($theme, scrollbar-x-height); + } + &:hover, + &:active { + > .ps__scrollbar-x { + height: map_get($theme, scrollbar-x-hover-height); + } + } + } + + > .ps__scrollbar-y-rail { + @include scrollbar-rail-default($theme); + right: map_get($theme, scrollbar-y-rail-right); /* there must be 'right' for ps__scrollbar-y-rail */ + width: map_get($theme, scrollbar-y-rail-width); + + > .ps__scrollbar-y { + @include scrollbar-default($theme); + right: map_get($theme, scrollbar-y-right); /* there must be 'right' for ps__scrollbar-y */ + width: map_get($theme, scrollbar-y-width); + } + &:hover, + &:active { + > .ps__scrollbar-y { + width: map_get($theme, scrollbar-y-hover-width); + } + } + } + + &:hover { + @include in-scrolling($theme); + + > .ps__scrollbar-x-rail, + > .ps__scrollbar-y-rail { + opacity: map_get($theme, rail-container-hover-opacity); + } + + > .ps__scrollbar-x-rail:hover { + @include scrollbar-rail-hover($theme); + + > .ps__scrollbar-x { + @include scrollbar-hover($theme); + } + } + + > .ps__scrollbar-y-rail:hover { + @include scrollbar-rail-hover($theme); + + > .ps__scrollbar-y { + @include scrollbar-hover($theme); + } + } + } +} \ No newline at end of file diff --git a/_sass/perfect-scrollbar/_perfect-scrollbar.scss b/_sass/perfect-scrollbar/_perfect-scrollbar.scss new file mode 100644 index 0000000..9facda7 --- /dev/null +++ b/_sass/perfect-scrollbar/_perfect-scrollbar.scss @@ -0,0 +1,116 @@ +/* + * Container style + */ +.ps { + overflow: hidden !important; + overflow-anchor: none; + -ms-overflow-style: none; + touch-action: auto; + -ms-touch-action: auto; +} + +/* + * Scrollbar rail styles + */ +.ps__rail-x { + display: none; + opacity: 0; + transition: background-color .2s linear, opacity .2s linear; + -webkit-transition: background-color .2s linear, opacity .2s linear; + height: 15px; + /* there must be 'bottom' or 'top' for ps__rail-x */ + bottom: 0px; + /* please don't change 'position' */ + position: absolute; +} + +.ps__rail-y { + display: none; + opacity: 0; + transition: background-color .2s linear, opacity .2s linear; + -webkit-transition: background-color .2s linear, opacity .2s linear; + width: 15px; + /* there must be 'right' or 'left' for ps__rail-y */ + right: 0; + /* please don't change 'position' */ + position: absolute; +} + +.ps--active-x > .ps__rail-x, +.ps--active-y > .ps__rail-y { + display: block; + background-color: transparent; +} + +.ps:hover > .ps__rail-x, +.ps:hover > .ps__rail-y, +.ps--focus > .ps__rail-x, +.ps--focus > .ps__rail-y, +.ps--scrolling-x > .ps__rail-x, +.ps--scrolling-y > .ps__rail-y { + opacity: 0.6; +} + +.ps .ps__rail-x:hover, +.ps .ps__rail-y:hover, +.ps .ps__rail-x:focus, +.ps .ps__rail-y:focus, +.ps .ps__rail-x.ps--clicking, +.ps .ps__rail-y.ps--clicking { + background-color: #eee; + opacity: 0.9; +} + +/* + * Scrollbar thumb styles + */ +.ps__thumb-x { + background-color: #aaa; + border-radius: 6px; + transition: background-color .2s linear, height .2s ease-in-out; + -webkit-transition: background-color .2s linear, height .2s ease-in-out; + height: 6px; + /* there must be 'bottom' for ps__thumb-x */ + bottom: 2px; + /* please don't change 'position' */ + position: absolute; +} + +.ps__thumb-y { + background-color: #aaa; + border-radius: 6px; + transition: background-color .2s linear, width .2s ease-in-out; + -webkit-transition: background-color .2s linear, width .2s ease-in-out; + width: 6px; + /* there must be 'right' for ps__thumb-y */ + right: 2px; + /* please don't change 'position' */ + position: absolute; +} + +.ps__rail-x:hover > .ps__thumb-x, +.ps__rail-x:focus > .ps__thumb-x, +.ps__rail-x.ps--clicking .ps__thumb-x { + background-color: #999; + height: 11px; +} + +.ps__rail-y:hover > .ps__thumb-y, +.ps__rail-y:focus > .ps__thumb-y, +.ps__rail-y.ps--clicking .ps__thumb-y { + background-color: #999; + width: 11px; +} + +/* MS supports */ +@supports (-ms-overflow-style: none) { + .ps { + overflow: auto !important; + } +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .ps { + overflow: auto !important; + } +} \ No newline at end of file diff --git a/_sass/perfect-scrollbar/_themes.scss b/_sass/perfect-scrollbar/_themes.scss new file mode 100644 index 0000000..1d6372d --- /dev/null +++ b/_sass/perfect-scrollbar/_themes.scss @@ -0,0 +1,25 @@ +$ps-theme-default: ( + border-radius: $ps-border-radius, + rail-default-opacity: $ps-rail-default-opacity, + rail-container-hover-opacity: $ps-rail-container-hover-opacity, + rail-hover-opacity: $ps-rail-hover-opacity, + bar-bg: $ps-bar-bg, + bar-container-hover-bg: $ps-bar-container-hover-bg, + bar-hover-bg: $ps-bar-hover-bg, + rail-hover-bg: $ps-rail-hover-bg, + scrollbar-x-rail-bottom: $ps-scrollbar-x-rail-bottom, + scrollbar-x-rail-height: $ps-scrollbar-x-rail-height, + scrollbar-x-bottom: $ps-scrollbar-x-bottom, + scrollbar-x-height: $ps-scrollbar-x-height, + scrollbar-x-hover-height: $ps-scrollbar-x-hover-height, + scrollbar-y-rail-right: $ps-scrollbar-y-rail-right, + scrollbar-y-rail-width: $ps-scrollbar-y-rail-width, + scrollbar-y-right: $ps-scrollbar-y-right, + scrollbar-y-width: $ps-scrollbar-y-width, + scrollbar-y-hover-width: $ps-scrollbar-y-hover-width, +); + +// Default theme +.ps { + @include ps-container($ps-theme-default); +} diff --git a/_sass/perfect-scrollbar/_variables.scss b/_sass/perfect-scrollbar/_variables.scss new file mode 100644 index 0000000..f11836e --- /dev/null +++ b/_sass/perfect-scrollbar/_variables.scss @@ -0,0 +1,24 @@ +// Colors +$ps-border-radius: 3px !default; + +$ps-rail-default-opacity: 0 !default; +$ps-rail-container-hover-opacity: 0.6 !default; +$ps-rail-hover-opacity: 0.9 !default; + +$ps-bar-bg: transparent !default; +$ps-bar-container-hover-bg: $bodyColour !default; +$ps-bar-hover-bg: $bodyColour !default; +$ps-rail-hover-bg: transparent !default; + +// Sizes +$ps-scrollbar-x-rail-bottom: 0px !default; +$ps-scrollbar-x-rail-height: 15px !default; +$ps-scrollbar-x-bottom: 2px !default; +$ps-scrollbar-x-height: 6px !default; +$ps-scrollbar-x-hover-height: 11px !default; + +$ps-scrollbar-y-rail-right: 0 !default; +$ps-scrollbar-y-rail-width: 15px !default; +$ps-scrollbar-y-right: 2px !default; +$ps-scrollbar-y-width: 8px !default; +$ps-scrollbar-y-hover-width: 8px !default; diff --git a/_sass/sassline/_sassline-variables.scss b/_sass/sassline/_sassline-variables.scss new file mode 100644 index 0000000..edabb5c --- /dev/null +++ b/_sass/sassline/_sassline-variables.scss @@ -0,0 +1,148 @@ +// SCSS variables +// --------------------------------------- + +// Note: For the following Sass maps enter values as if they would be px units. + +// Breakpoint sizes from px to ems. Add more values here to add more breakpoints. +// Change names if you prefer, it wont break the mixin as long as they are strings not just numbers. +$breakpoints: ( + break-0: 0, // 0px Mobile first + break-1: 640, // 640px ~ Small tablet up + break-2: 768, // 800px ~ Large tablet up + + // disabled a number of breakpoints -- + // break-3: 1024, // 1024px ~ Desktop up + // break-4: 1600 // 1600px ~ Large desktop up +) !default; + +// Root font-sizes for each breakpoint. Set to half desired line-height of body text. +// ! Make sure to have as many sizes as breakpoints above. +$rootsizes: ( + rootsize-0: 14, // 24px line-height body text + rootsize-1: 14, // 28px line-height body text + rootsize-2: 14, // 30px line-height body text + rootsize-3: 14, // 34px line-height body text + // rootsize-4: 14 // 38px line-height body text +) !default; + +// Set the optimum line-length for your text (based on typeface). +// Aim for 75–100 characters a line when possible, at smaller sizes type size is more important. +// ! Make sure to have as many widths as breakpoints above. +// Note: this was 'maxwidths' in previous versions. +$measures: ( + measure-0: 500, // 500px wide + measure-1: 550, // 550px wide + measure-2: 600, // 600px wide + measure-3: 680, // 680px wide + // measure-4: 750 // 750px wide +) !default; + +// Set the max-widths for containers (based on design). +// ! Make sure to have as many widths as breakpoints above. +$maxwidths: ( + width-0: 500, // 500px wide + width-1: 600, // 600px wide + width-2: 800, // 800px wide + width-3: 1100, // 110px wide + // width-4: 1300 // 1300px wide +) !default; + +// Gutter widths +$gutterwidths: ( + small: 0rem, + medium: 0rem, + large: 0rem +) !default; + +// Define defaults for each variable. + +$bodytype: ( + font-family: 'Times New Roman Seven, Times New Roman, serif', + regular: 300, + bold: 700, + italic: italic, + cap-height: .66 +) !default; + +$headingtype: ( + font-family: 'Lars, Helvetica Neue, sans-serif', + regular: 300, + bold: 700, + cap-height: .66 +) !default; + +$monospacetype: ( + font-family: 'Menlo, monospace', + regular: 400, + cap-height: 0.68 +) !default; + + +// Width of the content area +$content-width: 800px !default; +$on-palm: 768px !default; +$on-laptop: 1024px !default; + +// Use media queries like this: +// @include media-query($on-palm) { +// .wrapper { +// padding-right: $spacing-unit / 2; +// padding-left: $spacing-unit / 2; +// } +// } +@mixin media-query($device) { + @media screen and (max-width: $device) { + @content; + } +} + +// $headingColour: #DFDFDF !default; +// $bodyColour: #DFDFDF !default; +// // $linkColour: #D8BFD8 !default; +// $linkColour: #DFDFDF !default; +// $hoverColour: darken($bodyColour,25%) !default; +// $captionColour: #BDC8CC !default; +// $white: #FFFFFF !default; + +// Background colours. +// $backgroundColour: #16161D !default; +// $codeBackgroundColour: #F5F4F2 !default; + +// Background colours. +$backgroundColour: #16161D !default; +$codeBackgroundColour: #F5F4F2 !default; + +$headingColour: #DFDFDF !default; +$bodyColour: #DFDFDF !default; +/* Publishing as Practice Color Schemes */ + +// Resident Contrast Colors + +$bSalmon: #AE535C; +$bYellow: #FFE800; +$hwOrange: #FF6C2F; +$hwBlue: #0078BF; +$msFuschia: #FF48B0; +$msGreen: #19975D; + +// hardworking goodlooking scheme +// $PasP-primary: darken($hwBlue, 10%); +// $PasP-contrast: lighten($hwOrange, 2%); + +// martine syms scheme +// $PasP-contrast: lighten($msGreen,5%); +// $PasP-primary: $backgroundColour; + +// bidoun scheme +$PasP-contrast: $bYellow; +$PasP-primary: darken($bSalmon,5%); + + +// $linkColour: #D8BFD8 !default; +// $linkColour: #DFDFDF !default; +// $linkColour: $msGreen !default; +// $hoverColour: lighten($msGreen, 10%) !default; +$linkColour: $bYellow !default; +$hoverColour: lighten($bYellow, 35%) !default; +$captionColour: #BDC8CC !default; +$white: #FFFFFF !default; \ No newline at end of file diff --git a/_sass/sassline/modules/_footer.scss b/_sass/sassline/modules/_footer.scss new file mode 100644 index 0000000..3044bee --- /dev/null +++ b/_sass/sassline/modules/_footer.scss @@ -0,0 +1,16 @@ +// Footer demo styles. +// --------------------------------------- + +.global-footer { + + p { + @include fontsize(eta, all); + + color: $captionColour; + font-family: unquote(map-get($bodytype, font-family)); + font-style: normal; + font-weight: map-get($headingtype, regular); + padding: 1rem 0; + margin: 0; + } +} diff --git a/_sass/sassline/modules/_globals.scss b/_sass/sassline/modules/_globals.scss new file mode 100644 index 0000000..bf620e6 --- /dev/null +++ b/_sass/sassline/modules/_globals.scss @@ -0,0 +1,37 @@ +// Global demo styles. +// --------------------------------------- + +body { + background-color: $backgroundColour; + color: $bodyColour; + overflow-x: hidden; +} + +.section { + padding: 2rem 0; + + @include breakpoint(break-1) { + padding: 3rem 0; + } + + @include breakpoint(break-2) { + padding: 4rem 0; + } +} + +img { + -ms-interpolation-mode: bicubic; + height: auto; + vertical-align: middle; + width: 100%; + + @include breakpoint(break-1) { + margin: 0 auto; + max-width: 100%; + width: auto; + } +} + +.button-align { + @include baseline(zeta, $bodytype, 2, 2, all); +} diff --git a/_sass/sassline/modules/_header.scss b/_sass/sassline/modules/_header.scss new file mode 100644 index 0000000..5dbf574 --- /dev/null +++ b/_sass/sassline/modules/_header.scss @@ -0,0 +1,32 @@ +// Header demo styles. +// --------------------------------------- + +.global-header { + background-color: $backgroundColour; + font-size: 0; + + .global-header__logo { + background-image: url(../img/sassline-logo.svg); + background-size: 132px 19px; + color: transparent; + display: inline-block; + font: 0/0 a; + height: 19px; + margin: 2rem 0 2rem 3%; + position: relative; + vertical-align: middle; + width: 132px; + + @include breakpoint(break-1) { + margin-left: 2rem; + } + + a { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + } + } +} diff --git a/_sass/sassline/modules/_nav.scss b/_sass/sassline/modules/_nav.scss new file mode 100644 index 0000000..f4c0dad --- /dev/null +++ b/_sass/sassline/modules/_nav.scss @@ -0,0 +1,175 @@ +// Navigation demo styles. +// --------------------------------------- + +// responsive-nav.js styles. +.nav-collapse { + + ul { + display: block; + list-style: none; + margin: 0; + padding: 0; + width: 100%; + } + + li { + display: block; + width: 100%; + } + + &.opened { + max-height: 9999px; + } +} + +.js { + + .nav-collapse { + clip: rect(0 0 0 0); + display: block; + max-height: 0; + overflow: hidden; + position: absolute; + zoom: 1; + + @include breakpoint(break-1) { + max-height: none; + position: relative; + } + } +} + +.disable-pointer-events { + pointer-events: none; +} + +.nav-toggle { + -webkit-tap-highlight-color: rgba(0,0,0,0); + -webkit-touch-callout: none; + user-select: none; + + @include breakpoint(break-1) { + display: none; + } +} + +// Demo overrides. +.main-nav { + + @include breakpoint(break-1) { + display: inline-block; + width: calc(100% - 132px - 2rem); + vertical-align: middle; + } + + .main-nav__list { + border-top: 0.1rem solid darken($white, 15%); + + @include breakpoint(break-1) { + border: 0; + background-color: transparent; + margin-left: 0; + text-align: right; + width: 100%; + } + } + + li { + @include fontsize(16, 0); + + font-family: unquote(map-get($headingtype, font-family)); + font-style: normal; + font-weight: map-get($headingtype, regular); + + a, span { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + border-bottom: 0.1rem solid darken($white, 15%); + color: $linkColour; + cursor: pointer; + display: block; + padding: 10px 3%; + + &:hover, &:active, &:focus { + background-color: $linkColour; + color: $white; + } + } + + @include breakpoint(break-1) { + @include fontsize(12, 1); + + display: inline-block; + letter-spacing: 0.1rem; + margin-right: 2rem; + padding: 1rem 0; + text-transform: uppercase; + width: auto; + + a, span { + border: 0; + color: $captionColour; + display: inline; + padding: 0; + + &:hover, &:active, &:focus { + background-color: transparent; + color: $linkColour; + } + } + } + + @include breakpoint(break-2) { + @include fontsize(12, 2); + } + + // @include breakpoint(break-3) { + // @include fontsize(12, 3); + // } + + // @include breakpoint(break-4) { + // @include fontsize(12, 4); + // } + } +} + +.js { + + .nav-collapse { + + @include breakpoint(break-1) { + display: inline-block; + max-height: none; + position: relative; + } + } + + .nav-toggle { + display: block; + line-height: 0; + position: absolute; + right: 3%; + top: 1.3rem; + + &:after { + background-image: url(../img/menu.svg); + background-position: 0 0; + background-size: 30px 60px; + content: ''; + display: block; + height: 30px; + width: 30px; + } + + &.active:after { + background-position: 0 30px; + } + + @include breakpoint(break-1) { + display: none; + } + } +} diff --git a/_sass/sassline/modules/_show-grid.scss b/_sass/sassline/modules/_show-grid.scss new file mode 100644 index 0000000..50ad534 --- /dev/null +++ b/_sass/sassline/modules/_show-grid.scss @@ -0,0 +1,11 @@ +// Baseline grid demo styles. +// --------------------------------------- + +#baseline.show-grid { + background-image: -webkit-linear-gradient(to bottom, cyan 0, rgba(255,255,255,0) 1px); + background-image: -moz-linear-gradient(to bottom, cyan 0, rgba(255,255,255,0) 1px); + background-image: -o-linear-gradient(to bottom, cyan 0, rgba(255,255,255,0) 1px); + background-image: linear-gradient(to bottom, cyan 0, rgba(255,255,255,0) 1px); + background-repeat: repeat-y; + background-size: 100% 1rem; +} diff --git a/_sass/sassline/sassline-base/_layouts.scss b/_sass/sassline/sassline-base/_layouts.scss new file mode 100644 index 0000000..1cceae0 --- /dev/null +++ b/_sass/sassline/sassline-base/_layouts.scss @@ -0,0 +1,282 @@ +// Layouts +// --------------------------------------- + +// Container. +.section { + @include clearfix; + + margin: 0 auto; + position: relative; + width: 94%; + + // @include breakpoint(break-3) { + // @include maxwidth(3); + // } + + // @include breakpoint(break-4) { + // @include maxwidth(4); + // } +} + +// Single column (based on measure for typeset content). +.single-measure { + @include measure(all); + + margin: 0 auto; +} + +// Base column styles. +.column { + @include measure(0); + + margin: 0 auto; + width: 100%; + + @include breakpoint(break-1) { + float: left; + margin: initial; + max-width: initial; + padding-left: map-get($gutterwidths, small); + padding-right: map-get($gutterwidths, small); + } + + // @include breakpoint(break-3) { + // padding-left: map-get($gutterwidths, medium); + // padding-right: map-get($gutterwidths, medium); + // } +} + +// Two columns. +.column--duo { + + @include breakpoint(break-1) { + width: 50%; + + &:nth-of-type(2n+3) { + clear: left; + } + + &:nth-of-type(n+3) { + margin-top: 3rem; + } + } +} + +// Three columns. +.column--trio { + + @include breakpoint(break-1) { + width: 33.333%; + + &:nth-of-type(3n+4) { + clear: left; + } + + &:nth-of-type(n+4) { + margin-top: 3rem; + } + } +} + +// Four columns. Two at smaller breakpoints. +.column--quad { + + @include breakpoint(break-1) { + width: 50%; + } + + @include breakpoint(break-2) { + width: 25%; + } +} + +// Two column layout with a main text column and a sidebar. + +// Main column. +.column--main { + + @include breakpoint(break-1) { + @include ideal-measure(1, small); + } + + @include breakpoint(break-2) { + @include ideal-measure(2, small); + } + + // @include breakpoint(break-3) { + // @include ideal-measure(3, medium); + // } + + // @include breakpoint(break-4) { + // @include ideal-measure(4, medium); + // } +} + +// Sidebar. +.column--sidebar { + + @include breakpoint(break-1) { + @include ideal-measure(1, small, false); + + padding-right: map-get($gutterwidths, medium); + } + + @include breakpoint(break-2) { + @include ideal-measure(2, small, false); + } + + // @include breakpoint(break-3) { + // @include ideal-measure(3, medium, false); + + // padding-right: map-get($gutterwidths, large); + // } + + // @include breakpoint(break-4) { + // @include ideal-measure(4, medium, false); + // } +} + +// If sidebar on the right side. +.column--main + .column--sidebar { + @include breakpoint(break-1) { + padding-left: map-get($gutterwidths, medium); + padding-right: map-get($gutterwidths, small); + } + + // @include breakpoint(break-3) { + // padding-left: map-get($gutterwidths, large); + // padding-right: map-get($gutterwidths, medium); + // } +} + +// Set the main text one level down in the modular scale for narrower columns. +.column--trio, +.column--quad, +.column--sidebar { + + // @include breakpoint(break-3) { + + // p { + // @include sassline($fontsize: eta, $font: $bodytype, $lineheight: 2, $below: 2, $breakpoint: 3); + // } + + // li { + // @include fontsize(eta, 3); + // } + // } + + // @include breakpoint(break-4) { + + // p { + // @include sassline($fontsize: eta, $font: $bodytype, $lineheight: 2, $below: 2, $breakpoint: 4); + // } + + // li { + // @include fontsize(eta, 4); + // } + // } +} + +// Main column on the right with inline sidenotes. +// The sidenotes will move out the column into the sidebar position aligned to the baseline. +.column--right { + + @include breakpoint(break-1) { + @include ideal-measure(1, small); + @include ideal-measure(1, small, false, margin-left); + } + + @include breakpoint(break-2) { + @include ideal-measure(2, small); + @include ideal-measure(2, small, false, margin-left); + } + + // @include breakpoint(break-3) { + // @include ideal-measure(3, medium); + // @include ideal-measure(3, medium, false, margin-left); + // } + + // @include breakpoint(break-4) { + // @include ideal-measure(4, medium); + // @include ideal-measure(4, medium, false, margin-left); + // } + + .sidenote { + + @include breakpoint(break-1) { + @include ideal-measure(1, small, false); + + left: 0; + padding-left: map-get($gutterwidths, small); + padding-right: map-get($gutterwidths, medium); + position: absolute; + } + + @include breakpoint(break-2) { + @include ideal-measure(2, small, false); + } + + // @include breakpoint(break-3) { + // @include ideal-measure(3, medium, false); + + // padding-right: map-get($gutterwidths, large); + // } + + // @include breakpoint(break-4) { + // @include ideal-measure(4, medium, false); + + // padding-left: map-get($gutterwidths, medium); + // } + } +} + +// Main column on the left with inline sidenotes. +.column--left { + + @include breakpoint(break-1) { + @include ideal-measure(1, small); + } + + @include breakpoint(break-2) { + @include ideal-measure(2, small); + } + + // @include breakpoint(break-3) { + // @include ideal-measure(3, medium); + // } + + // @include breakpoint(break-4) { + // @include ideal-measure(4, medium); + // } + + .sidenote { + + @include breakpoint(break-1) { + @include ideal-measure(1, small, false); + @include ideal-measure(1, small, true, left); + + padding-left: map-get($gutterwidths, medium); + padding-right: map-get($gutterwidths, small); + position: absolute; + } + + @include breakpoint(break-2) { + @include ideal-measure(2, small, false); + @include ideal-measure(2, small, true, left); + } + + // @include breakpoint(break-3) { + // @include ideal-measure(3, medium, false); + // @include ideal-measure(3, medium, true, left); + + // padding-left: map-get($gutterwidths, large); + // } + + // @include breakpoint(break-4) { + // @include ideal-measure(4, medium, false); + // @include ideal-measure(4, medium, true, left); + + // padding-right: map-get($gutterwidths, medium); + // } + } +} diff --git a/_sass/sassline/sassline-base/_mixins.scss b/_sass/sassline/sassline-base/_mixins.scss new file mode 100644 index 0000000..49168e9 --- /dev/null +++ b/_sass/sassline/sassline-base/_mixins.scss @@ -0,0 +1,420 @@ +// SCSS mixins +// --------------------------------------- + +// Global variables used in mixins. + +// Number of breakpoints. +$breakpoints-limit: length($breakpoints); + +// List of rootsizes, breakpoints, and max-widths. +$sizes: map-values($rootsizes); +$points: map-values($breakpoints); +$line-widths: map-values($measures); +$max-widths: map-values($maxwidths); + + +// Breakpoints. Either set one to one of the breakpoint variables, or use a custom value for minor breakpoints. +// Defaults to min-width, but both min->max and max-width are available too. +// Parts based on https://gist.github.com/timknight/03e6335b8816aa534cf7 +@mixin breakpoint($break: 0, $max: 0) { + // Type of break variable + $value: type-of($break); + + // If it is a string (i.e. a breakpoint variable). + @if $value == string { + // If using 'break-1', 'break-2' etc output the correct breakpoints from map. + @if map-has-key($breakpoints, $break) { + @media screen and (min-width: #{map-get($breakpoints, $break) / 16 * 1em} ) { @content; } + } @else { + @warn "#{$break} is not a set breakpoint variable"; + } + + // If it is a number, use this for the breakpoint. + } @else if $value == number { + // If using other numbers output value in ems either for min, min & max or max width breakpoints. + $query: "all" !default; + @if $break != 0 and $max != 0 { $query: "(min-width: #{$break / 16 * 1em}) and (max-width: #{$max / 16 * 1em})"; } + @else if $break != 0 and $max == 0 { $query: "(min-width: #{$break / 16 * 1em})"; } + @else if $break == 0 and $max != 0 { $query: "(max-width: #{$max / 16 * 1em})"; } + @media #{$query} { @content; } + + } @else { + @warn "#{$break} is not valid to use as a breakpoint"; + } +} + +// Root font-size in %, outputted in correct breakpoints. +@mixin rootsize { + font-size: nth($sizes, 1) / 16 * 100%; + + // Loop through breakpoints. + @for $i from 2 through $breakpoints-limit { + @media screen and (min-width: nth($points, $i) / 16 * 1em ) { + font-size: nth($sizes, $i) / 16 * 100%; + } + } +} + +// Max-widths for typeset containers, outputted in correct breakpoints. +@mixin maxwidth($breakpoint: 0) { + // Type of chosen variables. + $break-value: type-of($breakpoint); + + // If specifying a breakpoint to use (and breakpoint exists). + @if $break-value == number and $breakpoint <= ($breakpoints-limit - 1) and $breakpoint >= 0 { + + max-width: #{nth($max-widths, ($breakpoint + 1)) / nth($sizes, ($breakpoint + 1))}rem; + + } @else if $breakpoint == all { + max-width: #{nth($max-widths, 1) / nth($sizes, 1)}rem; + + // Loop through breakpoints. + @for $i from 2 through $breakpoints-limit { + @media screen and (min-width: nth($points, $i) / 16 * 1em ) { + max-width: #{nth($max-widths, $i) / nth($sizes, $i)}rem; + } + } + } +} + +// Set the measure for single columns, outputted in correct breakpoints. +@mixin measure($breakpoint: 0) { + // Type of chosen variables. + $break-value: type-of($breakpoint); + + // If specifying a breakpoint to use (and breakpoint exists). + @if $break-value == number and $breakpoint <= ($breakpoints-limit - 1) and $breakpoint >= 0 { + + max-width: #{nth($line-widths, ($breakpoint + 1)) / nth($sizes, ($breakpoint + 1))}rem; + + } @else if $breakpoint == all { + max-width: #{nth($line-widths, 1) / nth($sizes, 1)}rem; + + // Loop through breakpoints. + @for $i from 2 through $breakpoints-limit { + @media screen and (min-width: nth($points, $i) / 16 * 1em ) { + max-width: #{nth($line-widths, $i) / nth($sizes, $i)}rem; + } + } + } +} + +// Calculate percentage width of container to get optimal measure for main text columns. +// Defaults to all breakpoints. +// Note: will not output for base breakpoint as this comes from the 'measure' mixin. +@mixin ideal-measure($breakpoint: 0, $gutter: 0, $main: true, $output: max-width) { + // Type of chosen variables. + $break-value: type-of($breakpoint); + + // If specifying a breakpoint to use (and breakpoint exists and is larger than 0). + @if $break-value == number and $breakpoint <= ($breakpoints-limit - 1) and $breakpoint > 0 { + + @if $gutter == small { + $gutter: map-get($gutterwidths, small) * 2 / 1rem; + } @else if $gutter == medium { + $gutter: map-get($gutterwidths, medium) * 2 / 1rem; + } @else if $gutter == large { + $gutter: map-get($gutterwidths, large) * 2 / 1rem; + } @else { + $gutter: 0; + } + + $rootsize: map-get($rootsizes, rootsize-#{$breakpoint}); + $ideal-measure: map-get($measures, measure-#{$breakpoint}); + $gutter-size: ($gutter * $rootsize); + $container-width: map-get($maxwidths, width-#{$breakpoint}); + + $percentage: percentage(($ideal-measure + $gutter-size) / $container-width); + + @if $percentage < 55 { + $percentage: 55%; + } @else if $percentage > 65 { + $percentage: 65%; + } + + @if $main == false { + $percentage: 100 - $percentage; + } + + #{$output}: $percentage; + } +} + +// Value in scale in $modular-scale? +// Used in following fontsize mixin. +@function in-modular-scale($scale, $key) { + $map: map-get($modular-scale, $scale); + $output: map-has-key($map, $key); + @return $output; +} + +// Font-size in rems. Either set per breakpoint or for all. +// Use values as you would for pixels i.e. 16 or use values from the modular scale. +@mixin fontsize($fontsize, $breakpoint: 0) { + // Type of chosen variables. + $font-value: type-of($fontsize); + $break-value: type-of($breakpoint); + + // Check if value exists in scale. + $in-scale: in-modular-scale(scale-0, $fontsize); + + // If specifying a breakpoint to use (and breakpoint exists). + @if $break-value == number and $breakpoint <= ($breakpoints-limit - 1) and $breakpoint >= 0 { + + // If using a number for fontsize. + @if $font-value == number { + font-size: #{$fontsize / nth($sizes, ($breakpoint + 1))}rem; + + // If using a variable from the scale for fontsize. + } @else if $in-scale == true { + $get-scale: map-get($modular-scale, scale-#{$breakpoint}); + $get-size: map-get($get-scale, $fontsize); + + font-size: #{$get-size / nth($sizes, ($breakpoint + 1))}rem; + + } @else { + @warn "#{$fontsize} is not a valid scale variable"; + } + + // If want to use value for all breakpoints. + } @else if $breakpoint == all { + + // If using a number for fontsize. + @if $font-value == number { + font-size: #{$fontsize / nth($sizes, 1)}rem; + + // Loop through breakpoints. + @for $i from 2 through $breakpoints-limit { + @media screen and (min-width: nth($points, $i) / 16 * 1em ) { + font-size: #{$fontsize / nth($sizes, $i)}rem; + } + } + + // If using a variable from the scale for fontsize. + } @else if $in-scale == true { + $get-scale: map-get($modular-scale, scale-0); + $get-size: map-get($get-scale, $fontsize); + font-size: #{$get-size / nth($sizes, 1)}rem; + + // Loop through breakpoints. + @for $i from 2 through $breakpoints-limit { + $get-scale: map-get($modular-scale, scale-#{$i - 1}); + $get-size: map-get($get-scale, $fontsize); + + @media screen and (min-width: nth($points, $i) / 16 * 1em ) { + font-size: #{$get-size / nth($sizes, $i)}rem; + } + } + + } @else { + @warn "#{$fontsize} is not a valid scale variable"; + } + + } @else { + @warn "#{$breakpoint} is not valid to use as a breakpoint"; + } +} + +// Advanced baseline magic. +// ! Read the README to help understand what is going on here. +// Parts based on https://gist.github.com/razwan/10662500 +@mixin baseline($fontsize, $font, $lineheight: 2, $below: 2, $breakpoint: 0) { + // Type of chosen variables. + $font-value: type-of($fontsize); + $break-value: type-of($breakpoint); + + // Cap height + $cap-height: map-get($font, cap-height); + + // Check if value exists in scale. + $in-scale: in-modular-scale(scale-0, $fontsize); + + // Set the line-height (if it isn’t set at 0). + @if $lineheight != 0 { + line-height: #{$lineheight}rem; + } + + // If specifying a breakpoint to use (and breakpoint exists). + @if $break-value == number and $breakpoint <= ($breakpoints-limit - 1) and $breakpoint >= 0 { + + // If using a number for fontsize. + @if $font-value == number { + $rootsize: nth($sizes, ($breakpoint + 1)); + $baseline-shift: #{($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001}; + $baseline-push: #{$below - (($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001)}; + + margin-bottom: #{$baseline-push}rem; + padding-top: #{$baseline-shift}rem; + + // If using a variable from the scale for fontsize. + } @else if $in-scale == true { + $get-scale: map-get($modular-scale, scale-#{$breakpoint}); + $get-size: map-get($get-scale, $fontsize); + $rootsize: nth($sizes, ($breakpoint + 1)); + + $baseline-shift: #{($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001}; + $baseline-push: #{$below - (($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001)}; + + margin-bottom: #{$baseline-push}rem; + padding-top: #{$baseline-shift}rem; + + } @else { + @warn "#{$fontsize} is not a valid scale variable"; + } + + // If want to use value for all breakpoints. + } @else if $breakpoint == all { + + // If using a number for fontsize. + @if $font-value == number { + $rootsize: nth($sizes, 1); + $baseline-shift: #{($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001}; + $baseline-push: #{$below - (($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001)}; + + margin-bottom: #{$baseline-push}rem; + padding-top: #{$baseline-shift}rem; + + // Loop through breakpoints. + @for $i from 2 through $breakpoints-limit { + $rootsize: nth($sizes, $i); + $baseline-shift: #{($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001}; + $baseline-push: #{$below - (($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001)}; + + @media screen and (min-width: nth($points, $i) / 16 * 1em ) { + margin-bottom: #{$baseline-push}rem; + padding-top: #{$baseline-shift}rem; + } + } + + // If using a variable from the scale for fontsize. + } @else if $in-scale == true { + $get-scale: map-get($modular-scale, scale-0); + $get-size: map-get($get-scale, $fontsize); + $rootsize: nth($sizes, 1); + + $baseline-shift: #{($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001}; + $baseline-push: #{$below - (($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001)}; + + margin-bottom: #{$baseline-push}rem; + padding-top: #{$baseline-shift}rem; + + // Loop through breakpoints. + @for $i from 2 through $breakpoints-limit { + $get-scale: map-get($modular-scale, scale-#{$i - 1}); + $get-size: map-get($get-scale, $fontsize); + $rootsize: nth($sizes, $i); + + $baseline-shift: #{($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001}; + $baseline-push: #{$below - (($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001)}; + + @media screen and (min-width: nth($points, $i) / 16 * 1em ) { + margin-bottom: #{$baseline-push}rem; + padding-top: #{$baseline-shift}rem; + } + } + + } @else { + @warn "#{$fontsize} is not a valid scale variable"; + } + + } @else { + @warn "#{$breakpoint} is not valid to use as a breakpoint"; + } +} + +// Set fontsize and baseline at once. Mix of fontsize and baseline mixin. +@mixin sassline($fontsize, $font, $lineheight: 2, $below: 2, $breakpoint: 0) { + $font-value: type-of($fontsize); + $break-value: type-of($breakpoint); + $cap-height: map-get($font, cap-height); + $in-scale: in-modular-scale(scale-0, $fontsize); + + line-height: #{$lineheight}rem; + + @if $break-value == number and $breakpoint <= ($breakpoints-limit - 1) and $breakpoint >= 0 { + + @if $font-value == number { + $rootsize: nth($sizes, ($breakpoint + 1)); + $baseline-shift: #{($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001}; + $baseline-push: #{$below - (($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001)}; + font-size: #{$fontsize / nth($sizes, ($breakpoint + 1))}rem; + margin-bottom: #{$baseline-push}rem; + padding-top: #{$baseline-shift}rem; + + } @else if $in-scale == true { + $get-scale: map-get($modular-scale, scale-#{$breakpoint}); + $get-size: map-get($get-scale, $fontsize); + $rootsize: nth($sizes, ($breakpoint + 1)); + $baseline-shift: #{($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001}; + $baseline-push: #{$below - (($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001)}; + font-size: #{$get-size / nth($sizes, ($breakpoint + 1))}rem; + margin-bottom: #{$baseline-push}rem; + padding-top: #{$baseline-shift}rem; + + } @else { + @warn "#{$fontsize} is not a valid scale variable"; + } + + } @else if $breakpoint == all { + + @if $font-value == number { + $rootsize: nth($sizes, 1); + $baseline-shift: #{($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001}; + $baseline-push: #{$below - (($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001)}; + font-size: #{$fontsize / nth($sizes, 1)}rem; + margin-bottom: #{$baseline-push}rem; + padding-top: #{$baseline-shift}rem; + + @for $i from 2 through $breakpoints-limit { + $rootsize: nth($sizes, $i); + $baseline-shift: #{($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001}; + $baseline-push: #{$below - (($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001)}; + @media screen and (min-width: nth($points, $i) / 16 * 1em ) { + font-size: #{$fontsize / nth($sizes, $i)}rem; + margin-bottom: #{$baseline-push}rem; + padding-top: #{$baseline-shift}rem; + } + } + + } @else if $in-scale == true { + $get-scale: map-get($modular-scale, scale-0); + $get-size: map-get($get-scale, $fontsize); + $rootsize: nth($sizes, 1); + $baseline-shift: #{($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001}; + $baseline-push: #{$below - (($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001)}; + font-size: #{$get-size / nth($sizes, 1)}rem; + margin-bottom: #{$baseline-push}rem; + padding-top: #{$baseline-shift}rem; + + @for $i from 2 through $breakpoints-limit { + $get-scale: map-get($modular-scale, scale-#{$i - 1}); + $get-size: map-get($get-scale, $fontsize); + $rootsize: nth($sizes, $i); + $baseline-shift: #{($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001}; + $baseline-push: #{$below - (($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001)}; + @media screen and (min-width: nth($points, $i) / 16 * 1em ) { + font-size: #{$get-size / nth($sizes, $i)}rem; + margin-bottom: #{$baseline-push}rem; + padding-top: #{$baseline-shift}rem; + } + } + + } @else { + @warn "#{$fontsize} is not a valid scale variable"; + } + + } @else { + @warn "#{$breakpoint} is not valid to use as a breakpoint"; + } +} + +// Clearfix. +@mixin clearfix { + &:before, &:after{ + display: table; + content: ""; + } + &:after{ + clear: both; + } +} diff --git a/_sass/sassline/sassline-base/_modular-scale.scss b/_sass/sassline/sassline-base/_modular-scale.scss new file mode 100644 index 0000000..cfbbe4d --- /dev/null +++ b/_sass/sassline/sassline-base/_modular-scale.scss @@ -0,0 +1,67 @@ +// Modular scale +// --------------------------------------- + +// Setting responsive modular-scales. Use appropriate scales for viewport sizes. +$modular-scale: ( + // Major Third http://www.modularscale.com/?16,28&px&1.25&web&text + scale-0: ( + alpha: 32.0, + beta: 28.1, + gamma: 25.6, + delta: 22.5, + epsilon: 20.5, + zeta: 18.0, + eta: 16.3, + theta: 14.4, + iota: 13.1 + ), + // Major Third http://www.modularscale.com/?17,30&px&1.25&web&text + scale-1: ( + alpha: 32.0, + beta: 28.1, + gamma: 25.6, + delta: 22.5, + epsilon: 20.5, + zeta: 18.0, + eta: 16.3, + theta: 14.4, + iota: 13.1 + ), +// http://www.modularscale.com/?19&&1.2&web&text +scale-2: ( + alpha: 47.28, + beta: 39.4, + gamma: 32.83, + delta: 27.36, + epsilon: 22.8, + zeta: 19, + eta: 15.83, + theta: 13.19, + iota: 11 + ), +// includes way too many breakpoints! +// // http://www.modularscale.com/?25,45&px&1.414&sass&text + // scale-3: ( + // alpha: 59.99, + // beta: 45, + // gamma: 33.76, + // delta: 25.33, + // epsilon: 26, + // zeta: 19.0, + // eta: 14.25, + // theta: 10.69, + // iota: 8.02 + // ), +// // http://www.modularscale.com/?19&px&1.333&sass&text +// scale-4: ( +// alpha: 59.99, +// beta: 45, +// gamma: 33.76, +// delta: 25.33, +// epsilon: 26, +// zeta: 19.0, +// eta: 14.25, +// theta: 10.69, +// iota: 8.02 +// ) +); diff --git a/_sass/sassline/sassline-base/_reset.scss b/_sass/sassline/sassline-base/_reset.scss new file mode 100644 index 0000000..13b1cc7 --- /dev/null +++ b/_sass/sassline/sassline-base/_reset.scss @@ -0,0 +1,13 @@ +// Reset +// --------------------------------------- + +// Reset all the things +* { box-sizing: border-box; } +html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } +article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } +html, body { height: 100%; } +a img { border: none; } +blockquote { quotes: none; } +blockquote:before, blockquote:after { content: ''; content: none; } +table { border-collapse: collapse; border-spacing: 0; } +caption, th, td { text-align: left; font-weight: normal; vertical-align: middle; } diff --git a/_sass/sassline/sassline-base/_typography.scss b/_sass/sassline/sassline-base/_typography.scss new file mode 100644 index 0000000..ca45313 --- /dev/null +++ b/_sass/sassline/sassline-base/_typography.scss @@ -0,0 +1,363 @@ +// Typography +// --------------------------------------- + +// Setting root sizes and base styles. +html { + @include rootsize; + + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +// Site-wide base styles. +body { + @include fontsize(zeta, all); + + font-family: unquote(map-get($bodytype, font-family)); + font-style: normal; + font-weight: map-get($bodytype, regular); + line-height: 2rem; +} + +// Links. +a { + color: $linkColour; + text-decoration: none; + transition: color .1s, background-color .1s; + + &:hover, &:active, &:focus { + color: $hoverColour; + text-decoration: none; + } +} + +// Styles for typeset text. +.typeset { + + // Nice underlines for text links. + p a, li a { + background-image: linear-gradient(to bottom,rgba(0, 0, 0, 0) 50%,lighten($linkColour,20%) 50%); + background-position: 0 93%; + background-repeat: repeat-x; + background-size: 100% 0.15rem; + text-shadow: 0.1rem 0 $backgroundColour, + 0.15rem 0 $backgroundColour, + -0.1rem 0 $backgroundColour, + -0.15rem 0 $backgroundColour; + + &:hover, &:active, &:focus { + background-image: linear-gradient(to bottom,rgba(0, 0, 0, 0) 50%,lighten($hoverColour,20%) 50%); + } + } + + // Paragraphs. OpenType ligatures and oldstyle figures enabled if available. + p { + @include baseline($fontsize: zeta, $font: $bodytype, $lineheight: 1.8, $below: 2, $breakpoint: all); + + font-feature-settings: 'kern', 'onum', 'liga'; + } + + // Headings. OpenType ligatures, discretionary ligatures and lining figures enabled if available. + h1, h2, h3, h4, h5, h6 { + color: $headingColour; + font-family: unquote(map-get($headingtype, font-family)); + font-feature-settings: 'dlig', 'liga', 'lnum', 'kern'; + font-style: normal; + font-weight: map-get($headingtype, regular); + } + + // Heading level 1. + h1, .alpha { + @include sassline($fontsize: alpha, $font: $headingtype, $lineheight: 3, $below: 1, $breakpoint: all); + } + + // Heading level 2. + h2, .beta { + @include sassline(beta, $headingtype, 3, 1, all); + } + + // Heading level 3. + h3, .gamma { + @include sassline(gamma, $headingtype, 3, 1, all); + } + + // Heading level 4. + h4, .delta { + @include sassline(delta, $headingtype, 2, 0, all); + } + + // Heading level 5. + h5, .epsilon { + @include sassline(epsilon, $headingtype, 2, 0, all); + } + + // Heading level 6. + h6, .zeta { + @include sassline(zeta, $headingtype, 2, 0, all); + } + + // Lists. + ul, ol { + @include baseline(zeta, $bodytype, 2, 2, all); + + li { + font-feature-settings: 'kern', 'onum', 'liga'; + margin-left: 2rem; + + @include breakpoint(break-1) { + margin-left: 0; + } + + ol, ul { + padding-top: 1rem; + margin-bottom: 1rem; + margin-left: 2rem; + } + } + } + + // Ordered lists. + ol { + list-style-type: none; + + li { + counter-increment: top-level; + + &:before { + content: counter(top-level) '.'; + font-feature-settings: 'lnum', 'tnum'; + margin-left: -3rem; + position: absolute; + text-align: right; + width: 2em; + } + + ul { + + li { + + &:before { + content: ''; + } + + ol { + + li { + counter-increment: alt-level; + + &:before { + content: counter(alt-level) '.'; + } + } + } + } + } + + ol { + + li { + counter-increment: sub-level; + + &:before { + content: counter(top-level) '.' counter(sub-level); + } + + ul { + + li { + + &:before { + content: ''; + } + } + } + + ol { + + li { + counter-increment: sub-sub-level; + + &:before { + content: counter(top-level) '.' counter(sub-level) '.' counter(sub-sub-level); + } + } + } + } + } + } + } + + // Definition lists. + dl { + @include baseline(zeta, $bodytype, 2, 2, all); + + dt, dd { + font-feature-settings: 'kern', 'onum', 'liga'; + margin-left: 2rem; + + @include breakpoint(break-1) { + margin-left: 0; + } + } + + dt { + font-weight: map-get($bodytype, bold); + } + + dd + dt { + padding-top: 1rem; + } + } + + // Tables. + table { + @include sassline(eta, $headingtype, 2, 0, all); + + font-family: unquote(map-get($headingtype, font-family)); + font-feature-settings: 'liga', 'lnum', 'tnum', 'kern'; + font-style: normal; + font-weight: map-get($headingtype, regular); + width: 100%; + + thead { + + th { + @include sassline(zeta, $headingtype, 2, 0, all); + padding-bottom: 1px; + } + } + } + + // Bold. + b, strong, .bold { + font-weight: map-get($bodytype, bold); + } + + // Italic. + em, i, .italic { + font-style: map-get($bodytype, italic); + } + + // Caption and inline small text. + small, .caption { + @include fontsize(theta, all); + + font-family: unquote(map-get($headingtype, font-family)); + font-style: normal; + font-weight: map-get($headingtype, regular); + } + + small { + line-height: 1rem; + } + + .caption { + @include baseline(theta, $headingtype, 2, 2, all); + + color: $captionColour; + } + + // Nice spacing for captions. + h1 + .caption, .alpha + .caption, h2 + .caption, .beta + .caption, h3 + .caption, .gamma + .caption { + margin-top: -1rem; + } + + .delta + .caption, .epsilon + .caption, .zeta + .caption { + margin-top: 0rem; + } + + // Quotes. + blockquote { + + p { + border-left: 0.15rem solid $linkColour; + font-style: map-get($bodytype, italic); + padding-left: 1rem; + + // Add spacing below blockquote paragraphs to align to baseline grid. + $get-scale: map-get($modular-scale, scale-0); + $get-size: map-get($get-scale, zeta); + $rootsize: nth($sizes, 1); + $baseline-shift: #{($get-size / 2 * ((2 * $rootsize / $get-size) - map-get($bodytype, cap-height))) / $rootsize + 0.00001}; + $baseline-push: #{3 - (($get-size * ((2 * $rootsize / $get-size) - map-get($bodytype, cap-height))) / $rootsize + 0.00001)}; + + margin-bottom: #{$baseline-push}rem; + padding-bottom: #{$baseline-shift}rem; + + @for $i from 2 through $breakpoints-limit { + $get-scale: map-get($modular-scale, scale-#{$i - 1}); + $get-size: map-get($get-scale, zeta); + $rootsize: nth($sizes, $i); + $baseline-shift: #{($get-size / 2 * ((2 * $rootsize / $get-size) - map-get($bodytype, cap-height))) / $rootsize + 0.00001}; + $baseline-push: #{3 - (($get-size * ((2 * $rootsize / $get-size) - map-get($bodytype, cap-height))) / $rootsize + 0.00001)}; + + @media screen and (min-width: nth($points, $i) / 16 * 1em ) { + margin-bottom: #{$baseline-push}rem; + padding-bottom: #{$baseline-shift}rem; + } + } + } + + @include breakpoint(break-1) { + margin-left: -1rem; + } + } + + // Horizontal rule. + hr { + background-image: linear-gradient(to bottom,rgba(0, 0, 0, 0) 50%,$captionColour 50%); + background-position: 0 50%; + background-repeat: repeat-x; + background-size: 100% 0.15rem; + border: 0; + margin: 0; + padding-bottom: 3rem; + padding-top: 3rem; + } + + // Code block. + code, pre { + background-color: $codeBackgroundColour; + font-family: unquote(map-get($monospacetype, font-family)); + } + + pre { + display: block; + margin-bottom: 2rem; + padding: 1rem; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; + } + + code { + @include fontsize(theta, all); + + line-height: 1rem; + } + + // Letter space those capitals people, Jan Tschichold would be proud. + .upper { + font-kerning: normal; + letter-spacing: 0.1rem; + text-transform: uppercase; + } + + // Real small caps. + .small-caps { + font-feature-settings: 'smcp', 'kern'; + font-kerning: normal; + letter-spacing: 0.1rem; + } + + // Consistent height numbers with OpenType. + .lining-numerals { + font-feature-settings: 'lnum', 'kern'; + } + + // Ascending and descending numbers with OpenType. + .oldstyle-numerals { + font-feature-settings: 'onum', 'kern'; + } +} diff --git a/_sass/sassline/style.scss b/_sass/sassline/style.scss new file mode 100755 index 0000000..5c06465 --- /dev/null +++ b/_sass/sassline/style.scss @@ -0,0 +1,12 @@ +/* CSS compiled from SCSS. */ +/* --------------------------------------- */ + +// Import Sassline base. +@import "sassline-base"; + +// Import your project SCSS module partials. +@import "modules/globals"; +@import "modules/nav"; +@import "modules/header"; +@import "modules/footer"; +@import "modules/show-grid"; diff --git a/admin/config.yml b/admin/config.yml new file mode 100644 index 0000000..853e462 --- /dev/null +++ b/admin/config.yml @@ -0,0 +1,29 @@ +# config.yml +backend: + name: github + repo: hello-ulises/ulises.us + branch: main + site_domain: pedantic-heyrovsky-2f6199.netlify.app + +media_folder: assets/img +site_url: http://ulises.us +display_url: http://ulises.us +logo_url: https://avatars.githubusercontent.com/u/23337776?s=200&v=4 +locale: en + +collections: + - name: 'posts' + label: 'Posts' + label_singular: 'Post' + folder: '_posts/' + create: true + slug: '{{year}}-{{month}}-{{day}}-{{slug}}' + fields: + - { name: 'title', label: 'Title', widget: 'string', description: 'This will appear as the post title' } + - { name: 'date', label: 'Date', widget: 'datetime', description: 'Date of post affects in which order posts appear', date_format: "YYYY-MM-DD" } + - { name: 'event_date', label: 'Event Date', widget: 'string', description: 'If applicable, enter date and time of event as it should appear in the text of the post', required: false } + - { name: 'layout', label: 'Layout', widget: 'hidden', default: 'post' } + - { name: 'categories', label: 'Column', widget: 'select', options: ["left", "right"], required: false } + - { name: 'tags', label: 'Tags', widget: 'select', multiple: true, options: ['sticky','active-voice','intimacy'], required: false } + - { name: 'published', label: 'Published', widget: 'boolean', default: true} + - { name: 'body', label: 'Body', widget: 'markdown'} diff --git a/admin/index.html b/admin/index.html new file mode 100644 index 0000000..2a9533d --- /dev/null +++ b/admin/index.html @@ -0,0 +1,11 @@ + + + + + + Content Manager + + + + + diff --git a/assets/css/main.scss b/assets/css/main.scss new file mode 100644 index 0000000..34a3144 --- /dev/null +++ b/assets/css/main.scss @@ -0,0 +1,46 @@ +--- +--- + +@font-face { + font-family: Lars; + src: + url('../font/Lars-Regular.woff2') format('woff2'), + url('../font/Lars-Regular.woff') format('woff'); + font-weight: 300; +} + +@font-face { + font-family: "Times New Roman Seven"; + src: url('../font/TimesNRSevenMT-Regular.woff') format('woff'); +} + +@font-face { + font-family: "Kadisoka"; + src: url('../font/kadisoka_script.woff') format('woff'); +} + +// Import Sassline partials. +@import "sassline/sassline-variables"; +@import "sassline/sassline-base/modular-scale"; +@import "sassline/sassline-base/mixins"; +@import "sassline/sassline-base/typography"; +@import "sassline/sassline-base/layouts"; + +@import "sassline/modules/globals"; +@import "sassline/modules/nav"; +@import "sassline/modules/header"; +@import "sassline/modules/footer"; +@import "sassline/modules/show-grid"; + +// Import Neat partials. +@import "neat/neat"; + +// Import Perfect Scrollbar + +// @import 'perfect-scrollbar/variables'; +// @import 'perfect-scrollbar/mixins'; +// @import 'perfect-scrollbar/themes'; +@import 'perfect-scrollbar/perfect-scrollbar'; + +// Import custom layouts +@import "layouts"; \ No newline at end of file diff --git a/assets/favicon/favicon-160x160.png b/assets/favicon/favicon-160x160.png new file mode 100644 index 0000000..ba532a9 Binary files /dev/null and b/assets/favicon/favicon-160x160.png differ diff --git a/assets/favicon/favicon-16x16.png b/assets/favicon/favicon-16x16.png new file mode 100644 index 0000000..80b79a7 Binary files /dev/null and b/assets/favicon/favicon-16x16.png differ diff --git a/assets/favicon/favicon-192x192.png b/assets/favicon/favicon-192x192.png new file mode 100644 index 0000000..143c544 Binary files /dev/null and b/assets/favicon/favicon-192x192.png differ diff --git a/assets/favicon/favicon-32x32.png b/assets/favicon/favicon-32x32.png new file mode 100644 index 0000000..5fc0759 Binary files /dev/null and b/assets/favicon/favicon-32x32.png differ diff --git a/assets/favicon/favicon-96x96.png b/assets/favicon/favicon-96x96.png new file mode 100644 index 0000000..3f0db99 Binary files /dev/null and b/assets/favicon/favicon-96x96.png differ diff --git a/assets/favicon/favicon.png b/assets/favicon/favicon.png new file mode 100644 index 0000000..5fc0759 Binary files /dev/null and b/assets/favicon/favicon.png differ diff --git a/assets/font/Lars-Regular.woff b/assets/font/Lars-Regular.woff new file mode 100644 index 0000000..4d9d976 Binary files /dev/null and b/assets/font/Lars-Regular.woff differ diff --git a/assets/font/Lars-Regular.woff2 b/assets/font/Lars-Regular.woff2 new file mode 100644 index 0000000..0d50105 Binary files /dev/null and b/assets/font/Lars-Regular.woff2 differ diff --git a/assets/font/TimesNRSevenMT-Regular.woff b/assets/font/TimesNRSevenMT-Regular.woff new file mode 100644 index 0000000..c265a21 Binary files /dev/null and b/assets/font/TimesNRSevenMT-Regular.woff differ diff --git a/assets/font/kadisoka_script.woff b/assets/font/kadisoka_script.woff new file mode 100755 index 0000000..0db30b6 Binary files /dev/null and b/assets/font/kadisoka_script.woff differ diff --git a/assets/font/kadisoka_script.woff2 b/assets/font/kadisoka_script.woff2 new file mode 100755 index 0000000..9324878 Binary files /dev/null and b/assets/font/kadisoka_script.woff2 differ diff --git a/assets/img/0425-DearReader.jpg b/assets/img/0425-DearReader.jpg new file mode 100644 index 0000000..0a775bb Binary files /dev/null and b/assets/img/0425-DearReader.jpg differ diff --git a/assets/img/07-NAOC-01.jpg b/assets/img/07-NAOC-01.jpg new file mode 100644 index 0000000..bc51177 Binary files /dev/null and b/assets/img/07-NAOC-01.jpg differ diff --git a/assets/img/10-carrion_thumb-2.jpg b/assets/img/10-carrion_thumb-2.jpg new file mode 100644 index 0000000..5e3ecde Binary files /dev/null and b/assets/img/10-carrion_thumb-2.jpg differ diff --git a/assets/img/11_SYMS_Notes-On-Gesture 183.jpg b/assets/img/11_SYMS_Notes-On-Gesture 183.jpg new file mode 100644 index 0000000..a18c8f4 Binary files /dev/null and b/assets/img/11_SYMS_Notes-On-Gesture 183.jpg differ diff --git a/assets/img/15. HAYES-2.jpg b/assets/img/15. HAYES-2.jpg new file mode 100644 index 0000000..1ea1d77 Binary files /dev/null and b/assets/img/15. HAYES-2.jpg differ diff --git a/assets/img/15. HAYES.jpg b/assets/img/15. HAYES.jpg new file mode 100644 index 0000000..8a87ad8 Binary files /dev/null and b/assets/img/15. HAYES.jpg differ diff --git a/assets/img/15895272_1251954841554748_1400330800993685810_n.jpg b/assets/img/15895272_1251954841554748_1400330800993685810_n.jpg new file mode 100644 index 0000000..c76e50e Binary files /dev/null and b/assets/img/15895272_1251954841554748_1400330800993685810_n.jpg differ diff --git a/assets/img/15bd428._HAYESbd428.jpg b/assets/img/15bd428._HAYESbd428.jpg new file mode 100644 index 0000000..1faa9a2 Binary files /dev/null and b/assets/img/15bd428._HAYESbd428.jpg differ diff --git a/assets/img/16998808_1089515417860400_7652733978941710275_n-680x680.jpg b/assets/img/16998808_1089515417860400_7652733978941710275_n-680x680.jpg new file mode 100644 index 0000000..7ef5771 Binary files /dev/null and b/assets/img/16998808_1089515417860400_7652733978941710275_n-680x680.jpg differ diff --git a/assets/img/18274858_1358834817533416_4529206522363639203_n.jpg b/assets/img/18274858_1358834817533416_4529206522363639203_n.jpg new file mode 100644 index 0000000..5ef4ed4 Binary files /dev/null and b/assets/img/18274858_1358834817533416_4529206522363639203_n.jpg differ diff --git a/assets/img/18556623_310192286079730_3304069030822008828_o.jpg b/assets/img/18556623_310192286079730_3304069030822008828_o.jpg new file mode 100644 index 0000000..ee7629c Binary files /dev/null and b/assets/img/18556623_310192286079730_3304069030822008828_o.jpg differ diff --git a/assets/img/2018_Martine_Syms_Dominica_Ulises_W-6.jpg b/assets/img/2018_Martine_Syms_Dominica_Ulises_W-6.jpg new file mode 100644 index 0000000..61da7cc Binary files /dev/null and b/assets/img/2018_Martine_Syms_Dominica_Ulises_W-6.jpg differ diff --git a/assets/img/2018_Ulises_Dominica_Opening-5091.jpg b/assets/img/2018_Ulises_Dominica_Opening-5091.jpg new file mode 100644 index 0000000..6028cf0 Binary files /dev/null and b/assets/img/2018_Ulises_Dominica_Opening-5091.jpg differ diff --git a/assets/img/2018_Ulises_Dominica_Opening-5164.jpg b/assets/img/2018_Ulises_Dominica_Opening-5164.jpg new file mode 100644 index 0000000..c5193f1 Binary files /dev/null and b/assets/img/2018_Ulises_Dominica_Opening-5164.jpg differ diff --git a/assets/img/2019_Ulises_Bidoun_Install_Event-4 (2).jpg b/assets/img/2019_Ulises_Bidoun_Install_Event-4 (2).jpg new file mode 100644 index 0000000..feeaa03 Binary files /dev/null and b/assets/img/2019_Ulises_Bidoun_Install_Event-4 (2).jpg differ diff --git a/assets/img/20988180_1468274746589422_4522942742685998601_o.jpg b/assets/img/20988180_1468274746589422_4522942742685998601_o.jpg new file mode 100644 index 0000000..cbf7163 Binary files /dev/null and b/assets/img/20988180_1468274746589422_4522942742685998601_o.jpg differ diff --git a/assets/img/26168859_1588964994520396_4701916880002131669_n.jpg b/assets/img/26168859_1588964994520396_4701916880002131669_n.jpg new file mode 100644 index 0000000..74ee8fa Binary files /dev/null and b/assets/img/26168859_1588964994520396_4701916880002131669_n.jpg differ diff --git a/assets/img/26805024_1601924936557735_4792805289535588420_n.jpg b/assets/img/26805024_1601924936557735_4792805289535588420_n.jpg new file mode 100644 index 0000000..7912e7e Binary files /dev/null and b/assets/img/26805024_1601924936557735_4792805289535588420_n.jpg differ diff --git a/assets/img/26840783_1602674933149402_8425449545268900409_o.jpg b/assets/img/26840783_1602674933149402_8425449545268900409_o.jpg new file mode 100644 index 0000000..b3e8613 Binary files /dev/null and b/assets/img/26840783_1602674933149402_8425449545268900409_o.jpg differ diff --git a/assets/img/27500209_10155333277445872_8427404642788443_o (1).jpg b/assets/img/27500209_10155333277445872_8427404642788443_o (1).jpg new file mode 100644 index 0000000..3ffebe9 Binary files /dev/null and b/assets/img/27500209_10155333277445872_8427404642788443_o (1).jpg differ diff --git a/assets/img/27500209_10155333277445872_8427404642788443_o.jpg b/assets/img/27500209_10155333277445872_8427404642788443_o.jpg new file mode 100644 index 0000000..3ffebe9 Binary files /dev/null and b/assets/img/27500209_10155333277445872_8427404642788443_o.jpg differ diff --git a/assets/img/37661338_1809499885800238_3356474872619335680_o.jpg b/assets/img/37661338_1809499885800238_3356474872619335680_o.jpg new file mode 100644 index 0000000..34f86a0 Binary files /dev/null and b/assets/img/37661338_1809499885800238_3356474872619335680_o.jpg differ diff --git a/assets/img/46984668_1984830651600493_4508748683273043968_o.jpg b/assets/img/46984668_1984830651600493_4508748683273043968_o.jpg new file mode 100644 index 0000000..9e82143 Binary files /dev/null and b/assets/img/46984668_1984830651600493_4508748683273043968_o.jpg differ diff --git a/assets/img/50276847_2060641054019452_3595583347029442560_o.jpg b/assets/img/50276847_2060641054019452_3595583347029442560_o.jpg new file mode 100644 index 0000000..4689cda Binary files /dev/null and b/assets/img/50276847_2060641054019452_3595583347029442560_o.jpg differ diff --git a/assets/img/51036544_2077928858957338_5925207615930892288_n.jpg b/assets/img/51036544_2077928858957338_5925207615930892288_n.jpg new file mode 100644 index 0000000..1089be6 Binary files /dev/null and b/assets/img/51036544_2077928858957338_5925207615930892288_n.jpg differ diff --git a/assets/img/53674801_2119187174831506_8420242654633132032_n.jpg b/assets/img/53674801_2119187174831506_8420242654633132032_n.jpg new file mode 100644 index 0000000..c014ad9 Binary files /dev/null and b/assets/img/53674801_2119187174831506_8420242654633132032_n.jpg differ diff --git a/assets/img/54379024_2140529272697296_8002580552798437376_o.jpg b/assets/img/54379024_2140529272697296_8002580552798437376_o.jpg new file mode 100644 index 0000000..4c4cc45 Binary files /dev/null and b/assets/img/54379024_2140529272697296_8002580552798437376_o.jpg differ diff --git a/assets/img/54731340_2134431356640421_3886286576371630080_o.jpg b/assets/img/54731340_2134431356640421_3886286576371630080_o.jpg new file mode 100644 index 0000000..2add0bc Binary files /dev/null and b/assets/img/54731340_2134431356640421_3886286576371630080_o.jpg differ diff --git a/assets/img/Adjunct.jpg b/assets/img/Adjunct.jpg new file mode 100644 index 0000000..cbb479f Binary files /dev/null and b/assets/img/Adjunct.jpg differ diff --git a/assets/img/BIO.gif b/assets/img/BIO.gif new file mode 100644 index 0000000..b0c91bc Binary files /dev/null and b/assets/img/BIO.gif differ diff --git a/assets/img/Ban1.jpg b/assets/img/Ban1.jpg new file mode 100644 index 0000000..ab9f1cb Binary files /dev/null and b/assets/img/Ban1.jpg differ diff --git a/assets/img/Bio_02.jpeg b/assets/img/Bio_02.jpeg new file mode 100644 index 0000000..8608cbf Binary files /dev/null and b/assets/img/Bio_02.jpeg differ diff --git a/assets/img/Bio_Cover-2.gif b/assets/img/Bio_Cover-2.gif new file mode 100644 index 0000000..4b14925 Binary files /dev/null and b/assets/img/Bio_Cover-2.gif differ diff --git a/assets/img/CarmenWinant.jpg b/assets/img/CarmenWinant.jpg new file mode 100644 index 0000000..43f1c89 Binary files /dev/null and b/assets/img/CarmenWinant.jpg differ diff --git a/assets/img/DSCF5080.jpeg b/assets/img/DSCF5080.jpeg new file mode 100644 index 0000000..cc50786 Binary files /dev/null and b/assets/img/DSCF5080.jpeg differ diff --git a/assets/img/GRAPHIC_Odds_2019_v2.jpg b/assets/img/GRAPHIC_Odds_2019_v2.jpg new file mode 100644 index 0000000..244371c Binary files /dev/null and b/assets/img/GRAPHIC_Odds_2019_v2.jpg differ diff --git a/assets/img/HardWorkingGoodLooking.gif b/assets/img/HardWorkingGoodLooking.gif new file mode 100644 index 0000000..25f09e9 Binary files /dev/null and b/assets/img/HardWorkingGoodLooking.gif differ diff --git a/assets/img/Hardworking Goodlooking_Mosquito_press-107 (5).jpg b/assets/img/Hardworking Goodlooking_Mosquito_press-107 (5).jpg new file mode 100644 index 0000000..988090f Binary files /dev/null and b/assets/img/Hardworking Goodlooking_Mosquito_press-107 (5).jpg differ diff --git a/assets/img/Hardworking Goodlooking_Mosquito_press-82 (2).jpg b/assets/img/Hardworking Goodlooking_Mosquito_press-82 (2).jpg new file mode 100644 index 0000000..3523437 Binary files /dev/null and b/assets/img/Hardworking Goodlooking_Mosquito_press-82 (2).jpg differ diff --git a/assets/img/Hardworking Goodlooking_Mosquito_press-82 (5).jpg b/assets/img/Hardworking Goodlooking_Mosquito_press-82 (5).jpg new file mode 100644 index 0000000..3523437 Binary files /dev/null and b/assets/img/Hardworking Goodlooking_Mosquito_press-82 (5).jpg differ diff --git a/assets/img/IMG_1744-730x470.jpg b/assets/img/IMG_1744-730x470.jpg new file mode 100644 index 0000000..e06367c Binary files /dev/null and b/assets/img/IMG_1744-730x470.jpg differ diff --git a/assets/img/IMG_3634.jpg b/assets/img/IMG_3634.jpg new file mode 100644 index 0000000..2cd52e3 Binary files /dev/null and b/assets/img/IMG_3634.jpg differ diff --git a/assets/img/IMG_4418.JPG b/assets/img/IMG_4418.JPG new file mode 100644 index 0000000..357504d Binary files /dev/null and b/assets/img/IMG_4418.JPG differ diff --git a/assets/img/IMG_5664.JPG b/assets/img/IMG_5664.JPG new file mode 100644 index 0000000..96cc766 Binary files /dev/null and b/assets/img/IMG_5664.JPG differ diff --git a/assets/img/IMG_6688.JPG b/assets/img/IMG_6688.JPG new file mode 100644 index 0000000..50cfb3d Binary files /dev/null and b/assets/img/IMG_6688.JPG differ diff --git a/assets/img/IMG_9377 (1).JPG b/assets/img/IMG_9377 (1).JPG new file mode 100644 index 0000000..f5029ed Binary files /dev/null and b/assets/img/IMG_9377 (1).JPG differ diff --git a/assets/img/Internship.jpg b/assets/img/Internship.jpg new file mode 100644 index 0000000..234cbed Binary files /dev/null and b/assets/img/Internship.jpg differ diff --git a/assets/img/KHSG_11_Lawrence_Abu_Hamdan_2015.jpeg b/assets/img/KHSG_11_Lawrence_Abu_Hamdan_2015.jpeg new file mode 100644 index 0000000..a885022 Binary files /dev/null and b/assets/img/KHSG_11_Lawrence_Abu_Hamdan_2015.jpeg differ diff --git a/assets/img/MarwaArsanios.jpg b/assets/img/MarwaArsanios.jpg new file mode 100644 index 0000000..b9630c4 Binary files /dev/null and b/assets/img/MarwaArsanios.jpg differ diff --git a/assets/img/Nato-3.jpg b/assets/img/Nato-3.jpg new file mode 100644 index 0000000..4cd81d1 Binary files /dev/null and b/assets/img/Nato-3.jpg differ diff --git a/assets/img/PHILLY_SHOW_FINAL-11x17-forweb.jpg b/assets/img/PHILLY_SHOW_FINAL-11x17-forweb.jpg new file mode 100644 index 0000000..4b92a4e Binary files /dev/null and b/assets/img/PHILLY_SHOW_FINAL-11x17-forweb.jpg differ diff --git a/assets/img/PabloHelguera.jpg b/assets/img/PabloHelguera.jpg new file mode 100644 index 0000000..a112960 Binary files /dev/null and b/assets/img/PabloHelguera.jpg differ diff --git a/assets/img/PastedGraphic-1.png b/assets/img/PastedGraphic-1.png new file mode 100644 index 0000000..f595642 Binary files /dev/null and b/assets/img/PastedGraphic-1.png differ diff --git a/assets/img/ResizedImage538430-Xaviera-Simmons-On-Sculpture-2-2011-David-Castillo-Gallery.jpg b/assets/img/ResizedImage538430-Xaviera-Simmons-On-Sculpture-2-2011-David-Castillo-Gallery.jpg new file mode 100644 index 0000000..3ebabce Binary files /dev/null and b/assets/img/ResizedImage538430-Xaviera-Simmons-On-Sculpture-2-2011-David-Castillo-Gallery.jpg differ diff --git a/assets/img/RezaAbdoh.jpg b/assets/img/RezaAbdoh.jpg new file mode 100644 index 0000000..e255f59 Binary files /dev/null and b/assets/img/RezaAbdoh.jpg differ diff --git a/assets/img/Screen Shot 2016-12-24 at 9.59.36 AM.png b/assets/img/Screen Shot 2016-12-24 at 9.59.36 AM.png new file mode 100644 index 0000000..4db52a4 Binary files /dev/null and b/assets/img/Screen Shot 2016-12-24 at 9.59.36 AM.png differ diff --git a/assets/img/Screen Shot 2019-08-17 at 3.47.31 PM.png b/assets/img/Screen Shot 2019-08-17 at 3.47.31 PM.png new file mode 100644 index 0000000..8b44ee5 Binary files /dev/null and b/assets/img/Screen Shot 2019-08-17 at 3.47.31 PM.png differ diff --git a/assets/img/Screen Shot 2019-08-17 at 4.02.28 PM.png b/assets/img/Screen Shot 2019-08-17 at 4.02.28 PM.png new file mode 100644 index 0000000..78c95c1 Binary files /dev/null and b/assets/img/Screen Shot 2019-08-17 at 4.02.28 PM.png differ diff --git a/assets/img/Screen Shot 2019-09-19 at 2.29.22 PM.png b/assets/img/Screen Shot 2019-09-19 at 2.29.22 PM.png new file mode 100644 index 0000000..6f1bb83 Binary files /dev/null and b/assets/img/Screen Shot 2019-09-19 at 2.29.22 PM.png differ diff --git a/assets/img/Screen Shot 2020-07-29 at 10.25.35 AM.png b/assets/img/Screen Shot 2020-07-29 at 10.25.35 AM.png new file mode 100644 index 0000000..cc2a718 Binary files /dev/null and b/assets/img/Screen Shot 2020-07-29 at 10.25.35 AM.png differ diff --git a/assets/img/Screen-Shot-2019-05-31-at-10.53.37-AM.png b/assets/img/Screen-Shot-2019-05-31-at-10.53.37-AM.png new file mode 100644 index 0000000..09df33f Binary files /dev/null and b/assets/img/Screen-Shot-2019-05-31-at-10.53.37-AM.png differ diff --git a/assets/img/Steffani Jemison Event.jpg b/assets/img/Steffani Jemison Event.jpg new file mode 100644 index 0000000..8311c45 Binary files /dev/null and b/assets/img/Steffani Jemison Event.jpg differ diff --git a/assets/img/Superunknown 2.jpg b/assets/img/Superunknown 2.jpg new file mode 100644 index 0000000..58941da Binary files /dev/null and b/assets/img/Superunknown 2.jpg differ diff --git a/assets/img/TITLE CARD.png b/assets/img/TITLE CARD.png new file mode 100644 index 0000000..dd7a9d1 Binary files /dev/null and b/assets/img/TITLE CARD.png differ diff --git a/assets/img/TTR Issue 10 (front cover).jpg b/assets/img/TTR Issue 10 (front cover).jpg new file mode 100644 index 0000000..c9581b6 Binary files /dev/null and b/assets/img/TTR Issue 10 (front cover).jpg differ diff --git a/assets/img/TTR-Issue-10-(front-cover)-2.gif b/assets/img/TTR-Issue-10-(front-cover)-2.gif new file mode 100644 index 0000000..2dafd01 Binary files /dev/null and b/assets/img/TTR-Issue-10-(front-cover)-2.gif differ diff --git a/assets/img/TTR-Issue-10-(front-cover).gif b/assets/img/TTR-Issue-10-(front-cover).gif new file mode 100644 index 0000000..a97d7aa Binary files /dev/null and b/assets/img/TTR-Issue-10-(front-cover).gif differ diff --git a/assets/img/TTR-Issue-10-3.gif b/assets/img/TTR-Issue-10-3.gif new file mode 100644 index 0000000..a849585 Binary files /dev/null and b/assets/img/TTR-Issue-10-3.gif differ diff --git a/assets/img/TTR-Issue-10.gif b/assets/img/TTR-Issue-10.gif new file mode 100644 index 0000000..3f7cd06 Binary files /dev/null and b/assets/img/TTR-Issue-10.gif differ diff --git a/assets/img/TTR-Issue-10b.gif b/assets/img/TTR-Issue-10b.gif new file mode 100644 index 0000000..faca091 Binary files /dev/null and b/assets/img/TTR-Issue-10b.gif differ diff --git a/assets/img/TTR-Issue-10c.gif b/assets/img/TTR-Issue-10c.gif new file mode 100644 index 0000000..fd76dca Binary files /dev/null and b/assets/img/TTR-Issue-10c.gif differ diff --git a/assets/img/TTR-Issue-10d.gif b/assets/img/TTR-Issue-10d.gif new file mode 100644 index 0000000..24c6e27 Binary files /dev/null and b/assets/img/TTR-Issue-10d.gif differ diff --git a/assets/img/The Blind Owl Still with Ron Athey.jpg b/assets/img/The Blind Owl Still with Ron Athey.jpg new file mode 100644 index 0000000..c5ce1ff Binary files /dev/null and b/assets/img/The Blind Owl Still with Ron Athey.jpg differ diff --git a/assets/img/The Blind Owl Still with Ron Athey.tif b/assets/img/The Blind Owl Still with Ron Athey.tif new file mode 100644 index 0000000..84994d0 Binary files /dev/null and b/assets/img/The Blind Owl Still with Ron Athey.tif differ diff --git a/assets/img/TitleLaunch.jpg b/assets/img/TitleLaunch.jpg new file mode 100644 index 0000000..6a20a05 Binary files /dev/null and b/assets/img/TitleLaunch.jpg differ diff --git a/assets/img/ULISES CARD3.jpg b/assets/img/ULISES CARD3.jpg new file mode 100644 index 0000000..7388d75 Binary files /dev/null and b/assets/img/ULISES CARD3.jpg differ diff --git a/assets/img/ULISES_MOCK_1---02.gif b/assets/img/ULISES_MOCK_1---02.gif new file mode 100644 index 0000000..c48c489 Binary files /dev/null and b/assets/img/ULISES_MOCK_1---02.gif differ diff --git a/assets/img/UlisesHolidayHours.jpg b/assets/img/UlisesHolidayHours.jpg new file mode 100644 index 0000000..6d5cb6d Binary files /dev/null and b/assets/img/UlisesHolidayHours.jpg differ diff --git a/assets/img/VendorPower4.jpg b/assets/img/VendorPower4.jpg new file mode 100644 index 0000000..afe1353 Binary files /dev/null and b/assets/img/VendorPower4.jpg differ diff --git a/assets/img/WHtGD_small.gif b/assets/img/WHtGD_small.gif new file mode 100644 index 0000000..07f69a1 Binary files /dev/null and b/assets/img/WHtGD_small.gif differ diff --git a/assets/img/_MG_0865.jpg b/assets/img/_MG_0865.jpg new file mode 100644 index 0000000..8e64c94 Binary files /dev/null and b/assets/img/_MG_0865.jpg differ diff --git a/assets/img/_MG_6884 (1).jpg b/assets/img/_MG_6884 (1).jpg new file mode 100644 index 0000000..84bf5ba Binary files /dev/null and b/assets/img/_MG_6884 (1).jpg differ diff --git a/assets/img/_MG_6884.jpg b/assets/img/_MG_6884.jpg new file mode 100644 index 0000000..9b36e6f Binary files /dev/null and b/assets/img/_MG_6884.jpg differ diff --git a/assets/img/alexdacorte.jpg b/assets/img/alexdacorte.jpg new file mode 100644 index 0000000..66eff98 Binary files /dev/null and b/assets/img/alexdacorte.jpg differ diff --git a/assets/img/artistbooks_7_36_26_60.jpeg b/assets/img/artistbooks_7_36_26_60.jpeg new file mode 100644 index 0000000..b141ee7 Binary files /dev/null and b/assets/img/artistbooks_7_36_26_60.jpeg differ diff --git a/assets/img/b85775fd-4335-47fa-ba25-80c6c9a901b1.JPG b/assets/img/b85775fd-4335-47fa-ba25-80c6c9a901b1.JPG new file mode 100644 index 0000000..8d54b34 Binary files /dev/null and b/assets/img/b85775fd-4335-47fa-ba25-80c6c9a901b1.JPG differ diff --git a/assets/img/badlands_no5_i_would_do_anything_for_love_2.jpg b/assets/img/badlands_no5_i_would_do_anything_for_love_2.jpg new file mode 100644 index 0000000..8fffa45 Binary files /dev/null and b/assets/img/badlands_no5_i_would_do_anything_for_love_2.jpg differ diff --git a/assets/img/becksuss-book-release.jpg b/assets/img/becksuss-book-release.jpg new file mode 100644 index 0000000..72d4545 Binary files /dev/null and b/assets/img/becksuss-book-release.jpg differ diff --git a/assets/img/bosabf-mainsocialtilesave-the-date-80.jpeg b/assets/img/bosabf-mainsocialtilesave-the-date-80.jpeg new file mode 100644 index 0000000..f63de16 Binary files /dev/null and b/assets/img/bosabf-mainsocialtilesave-the-date-80.jpeg differ diff --git a/assets/img/commonfield_facebook_post_3.png b/assets/img/commonfield_facebook_post_3.png new file mode 100644 index 0000000..e894243 Binary files /dev/null and b/assets/img/commonfield_facebook_post_3.png differ diff --git a/assets/img/commonfield_instagram_post_2.png b/assets/img/commonfield_instagram_post_2.png new file mode 100644 index 0000000..0b5e51f Binary files /dev/null and b/assets/img/commonfield_instagram_post_2.png differ diff --git a/assets/img/cover-ban-en-banlieue.jpg b/assets/img/cover-ban-en-banlieue.jpg new file mode 100644 index 0000000..70f448f Binary files /dev/null and b/assets/img/cover-ban-en-banlieue.jpg differ diff --git a/assets/img/cyqtjcDkxawx.jpg b/assets/img/cyqtjcDkxawx.jpg new file mode 100644 index 0000000..2c8a558 Binary files /dev/null and b/assets/img/cyqtjcDkxawx.jpg differ diff --git a/assets/img/dd2.png b/assets/img/dd2.png new file mode 100644 index 0000000..42f8bd6 Binary files /dev/null and b/assets/img/dd2.png differ diff --git a/assets/img/dear-reader.jpg b/assets/img/dear-reader.jpg new file mode 100644 index 0000000..c6b3466 Binary files /dev/null and b/assets/img/dear-reader.jpg differ diff --git a/assets/img/f8847e15-2a0b-4975-a75c-b5423bcd508c.JPG b/assets/img/f8847e15-2a0b-4975-a75c-b5423bcd508c.JPG new file mode 100644 index 0000000..9c8bd3b Binary files /dev/null and b/assets/img/f8847e15-2a0b-4975-a75c-b5423bcd508c.JPG differ diff --git a/assets/img/fall-of-communism.png b/assets/img/fall-of-communism.png new file mode 100644 index 0000000..0fdf37c Binary files /dev/null and b/assets/img/fall-of-communism.png differ diff --git a/assets/img/fechasulises (1) (1).jpg b/assets/img/fechasulises (1) (1).jpg new file mode 100644 index 0000000..7ee2476 Binary files /dev/null and b/assets/img/fechasulises (1) (1).jpg differ diff --git a/assets/img/https___hypebeast.com_image_2020_10_jenny-holzer-plan-your-vote-animations-info-1.jpg b/assets/img/https___hypebeast.com_image_2020_10_jenny-holzer-plan-your-vote-animations-info-1.jpg new file mode 100644 index 0000000..5253f3e Binary files /dev/null and b/assets/img/https___hypebeast.com_image_2020_10_jenny-holzer-plan-your-vote-animations-info-1.jpg differ diff --git a/assets/img/img_6060.jpg b/assets/img/img_6060.jpg new file mode 100644 index 0000000..df60fa4 Binary files /dev/null and b/assets/img/img_6060.jpg differ diff --git a/assets/img/index.jpeg b/assets/img/index.jpeg new file mode 100644 index 0000000..d856af3 Binary files /dev/null and b/assets/img/index.jpeg differ diff --git a/assets/img/jenny-holzer-plan-your-vote-animations-info-1.jpg b/assets/img/jenny-holzer-plan-your-vote-animations-info-1.jpg new file mode 100644 index 0000000..c283f2c Binary files /dev/null and b/assets/img/jenny-holzer-plan-your-vote-animations-info-1.jpg differ diff --git a/assets/img/kayla-romberger-publishing-practice-2017-05.jpg b/assets/img/kayla-romberger-publishing-practice-2017-05.jpg new file mode 100644 index 0000000..714b469 Binary files /dev/null and b/assets/img/kayla-romberger-publishing-practice-2017-05.jpg differ diff --git a/assets/img/love-optimized-workshop-animation.gif b/assets/img/love-optimized-workshop-animation.gif new file mode 100644 index 0000000..26afee6 Binary files /dev/null and b/assets/img/love-optimized-workshop-animation.gif differ diff --git a/assets/img/marwaarsanios3.jpg b/assets/img/marwaarsanios3.jpg new file mode 100644 index 0000000..df96d12 Binary files /dev/null and b/assets/img/marwaarsanios3.jpg differ diff --git a/assets/img/obv-earth-post.jpg b/assets/img/obv-earth-post.jpg new file mode 100644 index 0000000..dd11730 Binary files /dev/null and b/assets/img/obv-earth-post.jpg differ diff --git a/assets/img/odds_ends_2016.jpg b/assets/img/odds_ends_2016.jpg new file mode 100644 index 0000000..d9b3196 Binary files /dev/null and b/assets/img/odds_ends_2016.jpg differ diff --git a/assets/img/out_loud_web.jpeg b/assets/img/out_loud_web.jpeg new file mode 100644 index 0000000..d8667b7 Binary files /dev/null and b/assets/img/out_loud_web.jpeg differ diff --git a/assets/img/outloud-04-2.gif b/assets/img/outloud-04-2.gif new file mode 100644 index 0000000..b1a9438 Binary files /dev/null and b/assets/img/outloud-04-2.gif differ diff --git a/assets/img/outloud-04.gif b/assets/img/outloud-04.gif new file mode 100644 index 0000000..b53bb87 Binary files /dev/null and b/assets/img/outloud-04.gif differ diff --git a/assets/img/pasp.gif b/assets/img/pasp.gif new file mode 100644 index 0000000..790d57a Binary files /dev/null and b/assets/img/pasp.gif differ diff --git a/assets/img/pc_mag_RGB.svg b/assets/img/pc_mag_RGB.svg new file mode 100644 index 0000000..c18a6cc --- /dev/null +++ b/assets/img/pc_mag_RGB.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/img/peace.png b/assets/img/peace.png new file mode 100644 index 0000000..90d65bc Binary files /dev/null and b/assets/img/peace.png differ diff --git a/assets/img/peace_small.png b/assets/img/peace_small.png new file mode 100644 index 0000000..79b724c Binary files /dev/null and b/assets/img/peace_small.png differ diff --git a/assets/img/pmabf22_instagram_1080_square.jpg b/assets/img/pmabf22_instagram_1080_square.jpg new file mode 100644 index 0000000..5739470 Binary files /dev/null and b/assets/img/pmabf22_instagram_1080_square.jpg differ diff --git a/assets/img/politics-of-intimacy.jpg b/assets/img/politics-of-intimacy.jpg new file mode 100644 index 0000000..0e599c1 Binary files /dev/null and b/assets/img/politics-of-intimacy.jpg differ diff --git a/assets/img/press_play_flyer (3).jpg b/assets/img/press_play_flyer (3).jpg new file mode 100644 index 0000000..50ca4f6 Binary files /dev/null and b/assets/img/press_play_flyer (3).jpg differ diff --git a/assets/img/qbxfl_04.jpg b/assets/img/qbxfl_04.jpg new file mode 100644 index 0000000..9bf31ce Binary files /dev/null and b/assets/img/qbxfl_04.jpg differ diff --git a/assets/img/screen-shot-2023-03-03-at-10.31.59-pm.png b/assets/img/screen-shot-2023-03-03-at-10.31.59-pm.png new file mode 100644 index 0000000..0cbd35b Binary files /dev/null and b/assets/img/screen-shot-2023-03-03-at-10.31.59-pm.png differ diff --git a/assets/img/splash_2017.jpeg b/assets/img/splash_2017.jpeg new file mode 100644 index 0000000..52ea2db Binary files /dev/null and b/assets/img/splash_2017.jpeg differ diff --git a/assets/img/tothewholewideworld.jpg b/assets/img/tothewholewideworld.jpg new file mode 100644 index 0000000..0f15690 Binary files /dev/null and b/assets/img/tothewholewideworld.jpg differ diff --git a/assets/img/ulises-2023_production-files_02-02.jpg b/assets/img/ulises-2023_production-files_02-02.jpg new file mode 100644 index 0000000..21d4b84 Binary files /dev/null and b/assets/img/ulises-2023_production-files_02-02.jpg differ diff --git a/assets/img/ulises-sale_ig_01-06.jpg b/assets/img/ulises-sale_ig_01-06.jpg new file mode 100644 index 0000000..871e754 Binary files /dev/null and b/assets/img/ulises-sale_ig_01-06.jpg differ diff --git a/assets/img/unnamed (1).jpg b/assets/img/unnamed (1).jpg new file mode 100644 index 0000000..b0e685f Binary files /dev/null and b/assets/img/unnamed (1).jpg differ diff --git a/assets/img/unnamed (3).jpg b/assets/img/unnamed (3).jpg new file mode 100644 index 0000000..69aaae4 Binary files /dev/null and b/assets/img/unnamed (3).jpg differ diff --git a/assets/img/ups_fb_banner.jpeg b/assets/img/ups_fb_banner.jpeg new file mode 100644 index 0000000..5e60f57 Binary files /dev/null and b/assets/img/ups_fb_banner.jpeg differ diff --git a/assets/js/main.min.js b/assets/js/main.min.js new file mode 100644 index 0000000..ce0b86b --- /dev/null +++ b/assets/js/main.min.js @@ -0,0 +1,18577 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o breakpoint){ + + if ( psArray[0] == undefined ) { + var columnLeft = document.querySelector('#left'); + var columnRight = document.querySelector('#right'); + // var columnPasp = document.querySelector('.column#pasp'); + psArray[0] = new Ps(columnLeft, params); + psArray[1] = new Ps(columnRight, params); + // psArray[2] = new Ps(columnPasp, params); + } else { + + for(i = 0; i < 3; i++){ + + psArray[i].update(); + } + } + + } else { + + + if ( psArray[0] == undefined ) { return } + else { + for(i = 0; i < 3; i++){ + psArray[i].destroy(); + delete psArray[i]; + } + } + } + + } + + // sets infinite scroll on splash + + var el = $('.splash-panel .scroll-wrapper'); + var height = el.height() * 2; + var splash = $('.splash-panel a'); + var themes = ['default', 'inverse', 'hw', 'ms', 'ms2', 'bd']; + + el.on('scroll',_.throttle( function() { + + var el = $(this); + var currentTop = el.scrollTop(); + + if ( currentTop > height * 2) { + el.scrollTop(height); + } + if ( currentTop < height / 4) { + el.scrollTop(height); + } + if ( (Math.floor(currentTop) % 9) == 0) { + + splash.removeClass(); + splash.addClass(themes[Math.floor(Math.random()*themes.length)]); + } + + }, 150)); + + + + // function toggles classes on parent element + + function setExpandPanel(el) { + + var parent = el.data('parent'); + $('#' + parent + ' .excerpted').toggleClass('hide'); + $('#' + parent + ' .expanded').toggleClass('show'); + } + + // function reveal PasP panel on click + + function setRevealPasP(el,toggleClass) { + + var target = el.data('target'); + $('.' + target ).toggleClass(toggleClass); + } + + function checkHeaders() { + + if($(this).width() < 769) { + $('header.left').append(header.remove()); + } else { + $('header.right').append(header.remove()); + } + } + + // sets expand on info panel + + // handles on how titles appear based on screen width + + var header = $('.site-header .content-wrapper'); + + function init() { + + setPerfectScrollbars(params,breakpoint); + checkHeaders(); + $('#info-button').on('click', function(e){ + e.preventDefault(); + setExpandPanel($(e.currentTarget)); + }); + $('#splash-body-anchor').on('click', function(e){ + e.preventDefault(); + setRevealPasP($(e.currentTarget),'hide'); + }); + $('#pasp-reveal').on('click', function(e){ + e.preventDefault(); + if( $(window).width() > 768 ) { + setRevealPasP($(e.currentTarget),'reveal'); + $(e.currentTarget).find('svg').toggleClass('hide'); + } + }); + $('.pasp-reveal').on('click', function(e){ + e.preventDefault(); + if( $(window).width() < 769 ) { + setExpandPanel($(e.currentTarget)); + } + }); + } + + init() + + $(window).on('resize',function(){ + init(); + }); +}); +},{"lodash":2,"perfect-scrollbar":3}],2:[function(require,module,exports){ +(function (global){ +/** + * @license + * Lodash + * Copyright JS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ +;(function() { + + /** Used as a safe reference for `undefined` in pre-ES5 environments. */ + var undefined; + + /** Used as the semantic version number. */ + var VERSION = '4.17.10'; + + /** Used as the size to enable large array optimizations. */ + var LARGE_ARRAY_SIZE = 200; + + /** Error message constants. */ + var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.', + FUNC_ERROR_TEXT = 'Expected a function'; + + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED = '__lodash_hash_undefined__'; + + /** Used as the maximum memoize cache size. */ + var MAX_MEMOIZE_SIZE = 500; + + /** Used as the internal argument placeholder. */ + var PLACEHOLDER = '__lodash_placeholder__'; + + /** Used to compose bitmasks for cloning. */ + var CLONE_DEEP_FLAG = 1, + CLONE_FLAT_FLAG = 2, + CLONE_SYMBOLS_FLAG = 4; + + /** Used to compose bitmasks for value comparisons. */ + var COMPARE_PARTIAL_FLAG = 1, + COMPARE_UNORDERED_FLAG = 2; + + /** Used to compose bitmasks for function metadata. */ + var WRAP_BIND_FLAG = 1, + WRAP_BIND_KEY_FLAG = 2, + WRAP_CURRY_BOUND_FLAG = 4, + WRAP_CURRY_FLAG = 8, + WRAP_CURRY_RIGHT_FLAG = 16, + WRAP_PARTIAL_FLAG = 32, + WRAP_PARTIAL_RIGHT_FLAG = 64, + WRAP_ARY_FLAG = 128, + WRAP_REARG_FLAG = 256, + WRAP_FLIP_FLAG = 512; + + /** Used as default options for `_.truncate`. */ + var DEFAULT_TRUNC_LENGTH = 30, + DEFAULT_TRUNC_OMISSION = '...'; + + /** Used to detect hot functions by number of calls within a span of milliseconds. */ + var HOT_COUNT = 800, + HOT_SPAN = 16; + + /** Used to indicate the type of lazy iteratees. */ + var LAZY_FILTER_FLAG = 1, + LAZY_MAP_FLAG = 2, + LAZY_WHILE_FLAG = 3; + + /** Used as references for various `Number` constants. */ + var INFINITY = 1 / 0, + MAX_SAFE_INTEGER = 9007199254740991, + MAX_INTEGER = 1.7976931348623157e+308, + NAN = 0 / 0; + + /** Used as references for the maximum length and index of an array. */ + var MAX_ARRAY_LENGTH = 4294967295, + MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, + HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; + + /** Used to associate wrap methods with their bit flags. */ + var wrapFlags = [ + ['ary', WRAP_ARY_FLAG], + ['bind', WRAP_BIND_FLAG], + ['bindKey', WRAP_BIND_KEY_FLAG], + ['curry', WRAP_CURRY_FLAG], + ['curryRight', WRAP_CURRY_RIGHT_FLAG], + ['flip', WRAP_FLIP_FLAG], + ['partial', WRAP_PARTIAL_FLAG], + ['partialRight', WRAP_PARTIAL_RIGHT_FLAG], + ['rearg', WRAP_REARG_FLAG] + ]; + + /** `Object#toString` result references. */ + var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + asyncTag = '[object AsyncFunction]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + domExcTag = '[object DOMException]', + errorTag = '[object Error]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + mapTag = '[object Map]', + numberTag = '[object Number]', + nullTag = '[object Null]', + objectTag = '[object Object]', + promiseTag = '[object Promise]', + proxyTag = '[object Proxy]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + symbolTag = '[object Symbol]', + undefinedTag = '[object Undefined]', + weakMapTag = '[object WeakMap]', + weakSetTag = '[object WeakSet]'; + + var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + + /** Used to match empty string literals in compiled template source. */ + var reEmptyStringLeading = /\b__p \+= '';/g, + reEmptyStringMiddle = /\b(__p \+=) '' \+/g, + reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; + + /** Used to match HTML entities and HTML characters. */ + var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, + reUnescapedHtml = /[&<>"']/g, + reHasEscapedHtml = RegExp(reEscapedHtml.source), + reHasUnescapedHtml = RegExp(reUnescapedHtml.source); + + /** Used to match template delimiters. */ + var reEscape = /<%-([\s\S]+?)%>/g, + reEvaluate = /<%([\s\S]+?)%>/g, + reInterpolate = /<%=([\s\S]+?)%>/g; + + /** Used to match property names within property paths. */ + var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/, + rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; + + /** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ + var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, + reHasRegExpChar = RegExp(reRegExpChar.source); + + /** Used to match leading and trailing whitespace. */ + var reTrim = /^\s+|\s+$/g, + reTrimStart = /^\s+/, + reTrimEnd = /\s+$/; + + /** Used to match wrap detail comments. */ + var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, + reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, + reSplitDetails = /,? & /; + + /** Used to match words composed of alphanumeric characters. */ + var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; + + /** Used to match backslashes in property paths. */ + var reEscapeChar = /\\(\\)?/g; + + /** + * Used to match + * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). + */ + var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; + + /** Used to match `RegExp` flags from their coerced string values. */ + var reFlags = /\w*$/; + + /** Used to detect bad signed hexadecimal string values. */ + var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + + /** Used to detect binary string values. */ + var reIsBinary = /^0b[01]+$/i; + + /** Used to detect host constructors (Safari). */ + var reIsHostCtor = /^\[object .+?Constructor\]$/; + + /** Used to detect octal string values. */ + var reIsOctal = /^0o[0-7]+$/i; + + /** Used to detect unsigned integer values. */ + var reIsUint = /^(?:0|[1-9]\d*)$/; + + /** Used to match Latin Unicode letters (excluding mathematical operators). */ + var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; + + /** Used to ensure capturing order of template delimiters. */ + var reNoMatch = /($^)/; + + /** Used to match unescaped characters in compiled string literals. */ + var reUnescapedString = /['\n\r\u2028\u2029\\]/g; + + /** Used to compose unicode character classes. */ + var rsAstralRange = '\\ud800-\\udfff', + rsComboMarksRange = '\\u0300-\\u036f', + reComboHalfMarksRange = '\\ufe20-\\ufe2f', + rsComboSymbolsRange = '\\u20d0-\\u20ff', + rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, + rsDingbatRange = '\\u2700-\\u27bf', + rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff', + rsMathOpRange = '\\xac\\xb1\\xd7\\xf7', + rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf', + rsPunctuationRange = '\\u2000-\\u206f', + rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000', + rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde', + rsVarRange = '\\ufe0e\\ufe0f', + rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; + + /** Used to compose unicode capture groups. */ + var rsApos = "['\u2019]", + rsAstral = '[' + rsAstralRange + ']', + rsBreak = '[' + rsBreakRange + ']', + rsCombo = '[' + rsComboRange + ']', + rsDigits = '\\d+', + rsDingbat = '[' + rsDingbatRange + ']', + rsLower = '[' + rsLowerRange + ']', + rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']', + rsFitz = '\\ud83c[\\udffb-\\udfff]', + rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', + rsNonAstral = '[^' + rsAstralRange + ']', + rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', + rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', + rsUpper = '[' + rsUpperRange + ']', + rsZWJ = '\\u200d'; + + /** Used to compose unicode regexes. */ + var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')', + rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')', + rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?', + rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?', + reOptMod = rsModifier + '?', + rsOptVar = '[' + rsVarRange + ']?', + rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', + rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])', + rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])', + rsSeq = rsOptVar + reOptMod + rsOptJoin, + rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq, + rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; + + /** Used to match apostrophes. */ + var reApos = RegExp(rsApos, 'g'); + + /** + * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and + * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). + */ + var reComboMark = RegExp(rsCombo, 'g'); + + /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ + var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); + + /** Used to match complex or compound words. */ + var reUnicodeWord = RegExp([ + rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', + rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')', + rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower, + rsUpper + '+' + rsOptContrUpper, + rsOrdUpper, + rsOrdLower, + rsDigits, + rsEmoji + ].join('|'), 'g'); + + /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ + var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); + + /** Used to detect strings that need a more robust regexp to match words. */ + var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/; + + /** Used to assign default `context` object properties. */ + var contextProps = [ + 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', + 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', + 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', + 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', + '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' + ]; + + /** Used to make template sourceURLs easier to identify. */ + var templateCounter = -1; + + /** Used to identify `toStringTag` values of typed arrays. */ + var typedArrayTags = {}; + typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = + typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = + typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = + typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = + typedArrayTags[uint32Tag] = true; + typedArrayTags[argsTag] = typedArrayTags[arrayTag] = + typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = + typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = + typedArrayTags[errorTag] = typedArrayTags[funcTag] = + typedArrayTags[mapTag] = typedArrayTags[numberTag] = + typedArrayTags[objectTag] = typedArrayTags[regexpTag] = + typedArrayTags[setTag] = typedArrayTags[stringTag] = + typedArrayTags[weakMapTag] = false; + + /** Used to identify `toStringTag` values supported by `_.clone`. */ + var cloneableTags = {}; + cloneableTags[argsTag] = cloneableTags[arrayTag] = + cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = + cloneableTags[boolTag] = cloneableTags[dateTag] = + cloneableTags[float32Tag] = cloneableTags[float64Tag] = + cloneableTags[int8Tag] = cloneableTags[int16Tag] = + cloneableTags[int32Tag] = cloneableTags[mapTag] = + cloneableTags[numberTag] = cloneableTags[objectTag] = + cloneableTags[regexpTag] = cloneableTags[setTag] = + cloneableTags[stringTag] = cloneableTags[symbolTag] = + cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = + cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; + cloneableTags[errorTag] = cloneableTags[funcTag] = + cloneableTags[weakMapTag] = false; + + /** Used to map Latin Unicode letters to basic Latin letters. */ + var deburredLetters = { + // Latin-1 Supplement block. + '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', + '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', + '\xc7': 'C', '\xe7': 'c', + '\xd0': 'D', '\xf0': 'd', + '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', + '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', + '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', + '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', + '\xd1': 'N', '\xf1': 'n', + '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', + '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', + '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', + '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', + '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', + '\xc6': 'Ae', '\xe6': 'ae', + '\xde': 'Th', '\xfe': 'th', + '\xdf': 'ss', + // Latin Extended-A block. + '\u0100': 'A', '\u0102': 'A', '\u0104': 'A', + '\u0101': 'a', '\u0103': 'a', '\u0105': 'a', + '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C', + '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c', + '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd', + '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E', + '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e', + '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G', + '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g', + '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h', + '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I', + '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i', + '\u0134': 'J', '\u0135': 'j', + '\u0136': 'K', '\u0137': 'k', '\u0138': 'k', + '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L', + '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l', + '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N', + '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n', + '\u014c': 'O', '\u014e': 'O', '\u0150': 'O', + '\u014d': 'o', '\u014f': 'o', '\u0151': 'o', + '\u0154': 'R', '\u0156': 'R', '\u0158': 'R', + '\u0155': 'r', '\u0157': 'r', '\u0159': 'r', + '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S', + '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's', + '\u0162': 'T', '\u0164': 'T', '\u0166': 'T', + '\u0163': 't', '\u0165': 't', '\u0167': 't', + '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U', + '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u', + '\u0174': 'W', '\u0175': 'w', + '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y', + '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z', + '\u017a': 'z', '\u017c': 'z', '\u017e': 'z', + '\u0132': 'IJ', '\u0133': 'ij', + '\u0152': 'Oe', '\u0153': 'oe', + '\u0149': "'n", '\u017f': 's' + }; + + /** Used to map characters to HTML entities. */ + var htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + + /** Used to map HTML entities to characters. */ + var htmlUnescapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'" + }; + + /** Used to escape characters for inclusion in compiled string literals. */ + var stringEscapes = { + '\\': '\\', + "'": "'", + '\n': 'n', + '\r': 'r', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + /** Built-in method references without a dependency on `root`. */ + var freeParseFloat = parseFloat, + freeParseInt = parseInt; + + /** Detect free variable `global` from Node.js. */ + var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + + /** Detect free variable `self`. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || Function('return this')(); + + /** Detect free variable `exports`. */ + var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports = freeModule && freeModule.exports === freeExports; + + /** Detect free variable `process` from Node.js. */ + var freeProcess = moduleExports && freeGlobal.process; + + /** Used to access faster Node.js helpers. */ + var nodeUtil = (function() { + try { + // Use `util.types` for Node.js 10+. + var types = freeModule && freeModule.require && freeModule.require('util').types; + + if (types) { + return types; + } + + // Legacy `process.binding('util')` for Node.js < 10. + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} + }()); + + /* Node.js helper references. */ + var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, + nodeIsDate = nodeUtil && nodeUtil.isDate, + nodeIsMap = nodeUtil && nodeUtil.isMap, + nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, + nodeIsSet = nodeUtil && nodeUtil.isSet, + nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + + /*--------------------------------------------------------------------------*/ + + /** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ + function apply(func, thisArg, args) { + switch (args.length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); + } + + /** + * A specialized version of `baseAggregator` for arrays. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform keys. + * @param {Object} accumulator The initial aggregated object. + * @returns {Function} Returns `accumulator`. + */ + function arrayAggregator(array, setter, iteratee, accumulator) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + var value = array[index]; + setter(accumulator, value, iteratee(value), array); + } + return accumulator; + } + + /** + * A specialized version of `_.forEach` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEach(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.forEachRight` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEachRight(array, iteratee) { + var length = array == null ? 0 : array.length; + + while (length--) { + if (iteratee(array[length], length, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.every` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + */ + function arrayEvery(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; + } + + /** + * A specialized version of `_.filter` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function arrayFilter(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * A specialized version of `_.includes` for arrays without support for + * specifying an index to search from. + * + * @private + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @returns {boolean} Returns `true` if `target` is found, else `false`. + */ + function arrayIncludes(array, value) { + var length = array == null ? 0 : array.length; + return !!length && baseIndexOf(array, value, 0) > -1; + } + + /** + * This function is like `arrayIncludes` except that it accepts a comparator. + * + * @private + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @param {Function} comparator The comparator invoked per element. + * @returns {boolean} Returns `true` if `target` is found, else `false`. + */ + function arrayIncludesWith(array, value, comparator) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (comparator(value, array[index])) { + return true; + } + } + return false; + } + + /** + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function arrayMap(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; + } + + /** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ + function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; + + while (++index < length) { + array[offset + index] = values[index]; + } + return array; + } + + /** + * A specialized version of `_.reduce` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initAccum] Specify using the first element of `array` as + * the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduce(array, iteratee, accumulator, initAccum) { + var index = -1, + length = array == null ? 0 : array.length; + + if (initAccum && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } + return accumulator; + } + + /** + * A specialized version of `_.reduceRight` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initAccum] Specify using the last element of `array` as + * the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduceRight(array, iteratee, accumulator, initAccum) { + var length = array == null ? 0 : array.length; + if (initAccum && length) { + accumulator = array[--length]; + } + while (length--) { + accumulator = iteratee(accumulator, array[length], length, array); + } + return accumulator; + } + + /** + * A specialized version of `_.some` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function arraySome(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; + } + + /** + * Gets the size of an ASCII `string`. + * + * @private + * @param {string} string The string inspect. + * @returns {number} Returns the string size. + */ + var asciiSize = baseProperty('length'); + + /** + * Converts an ASCII `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function asciiToArray(string) { + return string.split(''); + } + + /** + * Splits an ASCII `string` into an array of its words. + * + * @private + * @param {string} The string to inspect. + * @returns {Array} Returns the words of `string`. + */ + function asciiWords(string) { + return string.match(reAsciiWord) || []; + } + + /** + * The base implementation of methods like `_.findKey` and `_.findLastKey`, + * without support for iteratee shorthands, which iterates over `collection` + * using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the found element or its key, else `undefined`. + */ + function baseFindKey(collection, predicate, eachFunc) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = key; + return false; + } + }); + return result; + } + + /** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseFindIndex(array, predicate, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 1 : -1); + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOf(array, value, fromIndex) { + return value === value + ? strictIndexOf(array, value, fromIndex) + : baseFindIndex(array, baseIsNaN, fromIndex); + } + + /** + * This function is like `baseIndexOf` except that it accepts a comparator. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @param {Function} comparator The comparator invoked per element. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOfWith(array, value, fromIndex, comparator) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (comparator(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.isNaN` without support for number objects. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + */ + function baseIsNaN(value) { + return value !== value; + } + + /** + * The base implementation of `_.mean` and `_.meanBy` without support for + * iteratee shorthands. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the mean. + */ + function baseMean(array, iteratee) { + var length = array == null ? 0 : array.length; + return length ? (baseSum(array, iteratee) / length) : NAN; + } + + /** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.propertyOf` without support for deep paths. + * + * @private + * @param {Object} object The object to query. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyOf(object) { + return function(key) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.reduce` and `_.reduceRight`, without support + * for iteratee shorthands, which iterates over `collection` using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} accumulator The initial value. + * @param {boolean} initAccum Specify using the first or last element of + * `collection` as the initial value. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the accumulated value. + */ + function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { + eachFunc(collection, function(value, index, collection) { + accumulator = initAccum + ? (initAccum = false, value) + : iteratee(accumulator, value, index, collection); + }); + return accumulator; + } + + /** + * The base implementation of `_.sortBy` which uses `comparer` to define the + * sort order of `array` and replaces criteria objects with their corresponding + * values. + * + * @private + * @param {Array} array The array to sort. + * @param {Function} comparer The function to define sort order. + * @returns {Array} Returns `array`. + */ + function baseSortBy(array, comparer) { + var length = array.length; + + array.sort(comparer); + while (length--) { + array[length] = array[length].value; + } + return array; + } + + /** + * The base implementation of `_.sum` and `_.sumBy` without support for + * iteratee shorthands. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the sum. + */ + function baseSum(array, iteratee) { + var result, + index = -1, + length = array.length; + + while (++index < length) { + var current = iteratee(array[index]); + if (current !== undefined) { + result = result === undefined ? current : (result + current); + } + } + return result; + } + + /** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ + function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; + } + + /** + * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array + * of key-value pairs for `object` corresponding to the property names of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the key-value pairs. + */ + function baseToPairs(object, props) { + return arrayMap(props, function(key) { + return [key, object[key]]; + }); + } + + /** + * The base implementation of `_.unary` without support for storing metadata. + * + * @private + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + */ + function baseUnary(func) { + return function(value) { + return func(value); + }; + } + + /** + * The base implementation of `_.values` and `_.valuesIn` which creates an + * array of `object` property values corresponding to the property names + * of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the array of property values. + */ + function baseValues(object, props) { + return arrayMap(props, function(key) { + return object[key]; + }); + } + + /** + * Checks if a `cache` value for `key` exists. + * + * @private + * @param {Object} cache The cache to query. + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function cacheHas(cache, key) { + return cache.has(key); + } + + /** + * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the first unmatched string symbol. + */ + function charsStartIndex(strSymbols, chrSymbols) { + var index = -1, + length = strSymbols.length; + + while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; + } + + /** + * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the last unmatched string symbol. + */ + function charsEndIndex(strSymbols, chrSymbols) { + var index = strSymbols.length; + + while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; + } + + /** + * Gets the number of `placeholder` occurrences in `array`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} placeholder The placeholder to search for. + * @returns {number} Returns the placeholder count. + */ + function countHolders(array, placeholder) { + var length = array.length, + result = 0; + + while (length--) { + if (array[length] === placeholder) { + ++result; + } + } + return result; + } + + /** + * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A + * letters to basic Latin letters. + * + * @private + * @param {string} letter The matched letter to deburr. + * @returns {string} Returns the deburred letter. + */ + var deburrLetter = basePropertyOf(deburredLetters); + + /** + * Used by `_.escape` to convert characters to HTML entities. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + var escapeHtmlChar = basePropertyOf(htmlEscapes); + + /** + * Used by `_.template` to escape characters for inclusion in compiled string literals. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + function escapeStringChar(chr) { + return '\\' + stringEscapes[chr]; + } + + /** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function getValue(object, key) { + return object == null ? undefined : object[key]; + } + + /** + * Checks if `string` contains Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a symbol is found, else `false`. + */ + function hasUnicode(string) { + return reHasUnicode.test(string); + } + + /** + * Checks if `string` contains a word composed of Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a word is found, else `false`. + */ + function hasUnicodeWord(string) { + return reHasUnicodeWord.test(string); + } + + /** + * Converts `iterator` to an array. + * + * @private + * @param {Object} iterator The iterator to convert. + * @returns {Array} Returns the converted array. + */ + function iteratorToArray(iterator) { + var data, + result = []; + + while (!(data = iterator.next()).done) { + result.push(data.value); + } + return result; + } + + /** + * Converts `map` to its key-value pairs. + * + * @private + * @param {Object} map The map to convert. + * @returns {Array} Returns the key-value pairs. + */ + function mapToArray(map) { + var index = -1, + result = Array(map.size); + + map.forEach(function(value, key) { + result[++index] = [key, value]; + }); + return result; + } + + /** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ + function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; + } + + /** + * Replaces all `placeholder` elements in `array` with an internal placeholder + * and returns an array of their indexes. + * + * @private + * @param {Array} array The array to modify. + * @param {*} placeholder The placeholder to replace. + * @returns {Array} Returns the new array of placeholder indexes. + */ + function replaceHolders(array, placeholder) { + var index = -1, + length = array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value === placeholder || value === PLACEHOLDER) { + array[index] = PLACEHOLDER; + result[resIndex++] = index; + } + } + return result; + } + + /** + * Gets the value at `key`, unless `key` is "__proto__". + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function safeGet(object, key) { + return key == '__proto__' + ? undefined + : object[key]; + } + + /** + * Converts `set` to an array of its values. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the values. + */ + function setToArray(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = value; + }); + return result; + } + + /** + * Converts `set` to its value-value pairs. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the value-value pairs. + */ + function setToPairs(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = [value, value]; + }); + return result; + } + + /** + * A specialized version of `_.indexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function strictIndexOf(array, value, fromIndex) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * A specialized version of `_.lastIndexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function strictLastIndexOf(array, value, fromIndex) { + var index = fromIndex + 1; + while (index--) { + if (array[index] === value) { + return index; + } + } + return index; + } + + /** + * Gets the number of symbols in `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the string size. + */ + function stringSize(string) { + return hasUnicode(string) + ? unicodeSize(string) + : asciiSize(string); + } + + /** + * Converts `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function stringToArray(string) { + return hasUnicode(string) + ? unicodeToArray(string) + : asciiToArray(string); + } + + /** + * Used by `_.unescape` to convert HTML entities to characters. + * + * @private + * @param {string} chr The matched character to unescape. + * @returns {string} Returns the unescaped character. + */ + var unescapeHtmlChar = basePropertyOf(htmlUnescapes); + + /** + * Gets the size of a Unicode `string`. + * + * @private + * @param {string} string The string inspect. + * @returns {number} Returns the string size. + */ + function unicodeSize(string) { + var result = reUnicode.lastIndex = 0; + while (reUnicode.test(string)) { + ++result; + } + return result; + } + + /** + * Converts a Unicode `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function unicodeToArray(string) { + return string.match(reUnicode) || []; + } + + /** + * Splits a Unicode `string` into an array of its words. + * + * @private + * @param {string} The string to inspect. + * @returns {Array} Returns the words of `string`. + */ + function unicodeWords(string) { + return string.match(reUnicodeWord) || []; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Create a new pristine `lodash` function using the `context` object. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Util + * @param {Object} [context=root] The context object. + * @returns {Function} Returns a new `lodash` function. + * @example + * + * _.mixin({ 'foo': _.constant('foo') }); + * + * var lodash = _.runInContext(); + * lodash.mixin({ 'bar': lodash.constant('bar') }); + * + * _.isFunction(_.foo); + * // => true + * _.isFunction(_.bar); + * // => false + * + * lodash.isFunction(lodash.foo); + * // => false + * lodash.isFunction(lodash.bar); + * // => true + * + * // Create a suped-up `defer` in Node.js. + * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; + */ + var runInContext = (function runInContext(context) { + context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps)); + + /** Built-in constructor references. */ + var Array = context.Array, + Date = context.Date, + Error = context.Error, + Function = context.Function, + Math = context.Math, + Object = context.Object, + RegExp = context.RegExp, + String = context.String, + TypeError = context.TypeError; + + /** Used for built-in method references. */ + var arrayProto = Array.prototype, + funcProto = Function.prototype, + objectProto = Object.prototype; + + /** Used to detect overreaching core-js shims. */ + var coreJsData = context['__core-js_shared__']; + + /** Used to resolve the decompiled source of functions. */ + var funcToString = funcProto.toString; + + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; + + /** Used to generate unique IDs. */ + var idCounter = 0; + + /** Used to detect methods masquerading as native. */ + var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; + }()); + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString = objectProto.toString; + + /** Used to infer the `Object` constructor. */ + var objectCtorString = funcToString.call(Object); + + /** Used to restore the original `_` reference in `_.noConflict`. */ + var oldDash = root._; + + /** Used to detect if a method is native. */ + var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); + + /** Built-in value references. */ + var Buffer = moduleExports ? context.Buffer : undefined, + Symbol = context.Symbol, + Uint8Array = context.Uint8Array, + allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, + getPrototype = overArg(Object.getPrototypeOf, Object), + objectCreate = Object.create, + propertyIsEnumerable = objectProto.propertyIsEnumerable, + splice = arrayProto.splice, + spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined, + symIterator = Symbol ? Symbol.iterator : undefined, + symToStringTag = Symbol ? Symbol.toStringTag : undefined; + + var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} + }()); + + /** Mocked built-ins. */ + var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout, + ctxNow = Date && Date.now !== root.Date.now && Date.now, + ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout; + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeCeil = Math.ceil, + nativeFloor = Math.floor, + nativeGetSymbols = Object.getOwnPropertySymbols, + nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, + nativeIsFinite = context.isFinite, + nativeJoin = arrayProto.join, + nativeKeys = overArg(Object.keys, Object), + nativeMax = Math.max, + nativeMin = Math.min, + nativeNow = Date.now, + nativeParseInt = context.parseInt, + nativeRandom = Math.random, + nativeReverse = arrayProto.reverse; + + /* Built-in method references that are verified to be native. */ + var DataView = getNative(context, 'DataView'), + Map = getNative(context, 'Map'), + Promise = getNative(context, 'Promise'), + Set = getNative(context, 'Set'), + WeakMap = getNative(context, 'WeakMap'), + nativeCreate = getNative(Object, 'create'); + + /** Used to store function metadata. */ + var metaMap = WeakMap && new WeakMap; + + /** Used to lookup unminified function names. */ + var realNames = {}; + + /** Used to detect maps, sets, and weakmaps. */ + var dataViewCtorString = toSource(DataView), + mapCtorString = toSource(Map), + promiseCtorString = toSource(Promise), + setCtorString = toSource(Set), + weakMapCtorString = toSource(WeakMap); + + /** Used to convert symbols to primitives and strings. */ + var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` object which wraps `value` to enable implicit method + * chain sequences. Methods that operate on and return arrays, collections, + * and functions can be chained together. Methods that retrieve a single value + * or may return a primitive value will automatically end the chain sequence + * and return the unwrapped value. Otherwise, the value must be unwrapped + * with `_#value`. + * + * Explicit chain sequences, which must be unwrapped with `_#value`, may be + * enabled using `_.chain`. + * + * The execution of chained methods is lazy, that is, it's deferred until + * `_#value` is implicitly or explicitly called. + * + * Lazy evaluation allows several methods to support shortcut fusion. + * Shortcut fusion is an optimization to merge iteratee calls; this avoids + * the creation of intermediate arrays and can greatly reduce the number of + * iteratee executions. Sections of a chain sequence qualify for shortcut + * fusion if the section is applied to an array and iteratees accept only + * one argument. The heuristic for whether a section qualifies for shortcut + * fusion is subject to change. + * + * Chaining is supported in custom builds as long as the `_#value` method is + * directly or indirectly included in the build. + * + * In addition to lodash methods, wrappers have `Array` and `String` methods. + * + * The wrapper `Array` methods are: + * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` + * + * The wrapper `String` methods are: + * `replace` and `split` + * + * The wrapper methods that support shortcut fusion are: + * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, + * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, + * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` + * + * The chainable wrapper methods are: + * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, + * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, + * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, + * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, + * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, + * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, + * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, + * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, + * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, + * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, + * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, + * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, + * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, + * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, + * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, + * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, + * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, + * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, + * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, + * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, + * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, + * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, + * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, + * `zipObject`, `zipObjectDeep`, and `zipWith` + * + * The wrapper methods that are **not** chainable by default are: + * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, + * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, + * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, + * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, + * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`, + * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`, + * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`, + * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, + * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, + * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, + * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, + * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, + * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, + * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, + * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, + * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, + * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, + * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, + * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, + * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, + * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, + * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, + * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, + * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, + * `upperFirst`, `value`, and `words` + * + * @name _ + * @constructor + * @category Seq + * @param {*} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var wrapped = _([1, 2, 3]); + * + * // Returns an unwrapped value. + * wrapped.reduce(_.add); + * // => 6 + * + * // Returns a wrapped value. + * var squares = wrapped.map(square); + * + * _.isArray(squares); + * // => false + * + * _.isArray(squares.value()); + * // => true + */ + function lodash(value) { + if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { + if (value instanceof LodashWrapper) { + return value; + } + if (hasOwnProperty.call(value, '__wrapped__')) { + return wrapperClone(value); + } + } + return new LodashWrapper(value); + } + + /** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} proto The object to inherit from. + * @returns {Object} Returns the new object. + */ + var baseCreate = (function() { + function object() {} + return function(proto) { + if (!isObject(proto)) { + return {}; + } + if (objectCreate) { + return objectCreate(proto); + } + object.prototype = proto; + var result = new object; + object.prototype = undefined; + return result; + }; + }()); + + /** + * The function whose prototype chain sequence wrappers inherit from. + * + * @private + */ + function baseLodash() { + // No operation performed. + } + + /** + * The base constructor for creating `lodash` wrapper objects. + * + * @private + * @param {*} value The value to wrap. + * @param {boolean} [chainAll] Enable explicit method chain sequences. + */ + function LodashWrapper(value, chainAll) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__chain__ = !!chainAll; + this.__index__ = 0; + this.__values__ = undefined; + } + + /** + * By default, the template delimiters used by lodash are like those in + * embedded Ruby (ERB) as well as ES2015 template strings. Change the + * following template settings to use alternative delimiters. + * + * @static + * @memberOf _ + * @type {Object} + */ + lodash.templateSettings = { + + /** + * Used to detect `data` property values to be HTML-escaped. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'escape': reEscape, + + /** + * Used to detect code to be evaluated. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'evaluate': reEvaluate, + + /** + * Used to detect `data` property values to inject. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'interpolate': reInterpolate, + + /** + * Used to reference the data object in the template text. + * + * @memberOf _.templateSettings + * @type {string} + */ + 'variable': '', + + /** + * Used to import variables into the compiled template. + * + * @memberOf _.templateSettings + * @type {Object} + */ + 'imports': { + + /** + * A reference to the `lodash` function. + * + * @memberOf _.templateSettings.imports + * @type {Function} + */ + '_': lodash + } + }; + + // Ensure wrappers are instances of `baseLodash`. + lodash.prototype = baseLodash.prototype; + lodash.prototype.constructor = lodash; + + LodashWrapper.prototype = baseCreate(baseLodash.prototype); + LodashWrapper.prototype.constructor = LodashWrapper; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. + * + * @private + * @constructor + * @param {*} value The value to wrap. + */ + function LazyWrapper(value) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__dir__ = 1; + this.__filtered__ = false; + this.__iteratees__ = []; + this.__takeCount__ = MAX_ARRAY_LENGTH; + this.__views__ = []; + } + + /** + * Creates a clone of the lazy wrapper object. + * + * @private + * @name clone + * @memberOf LazyWrapper + * @returns {Object} Returns the cloned `LazyWrapper` object. + */ + function lazyClone() { + var result = new LazyWrapper(this.__wrapped__); + result.__actions__ = copyArray(this.__actions__); + result.__dir__ = this.__dir__; + result.__filtered__ = this.__filtered__; + result.__iteratees__ = copyArray(this.__iteratees__); + result.__takeCount__ = this.__takeCount__; + result.__views__ = copyArray(this.__views__); + return result; + } + + /** + * Reverses the direction of lazy iteration. + * + * @private + * @name reverse + * @memberOf LazyWrapper + * @returns {Object} Returns the new reversed `LazyWrapper` object. + */ + function lazyReverse() { + if (this.__filtered__) { + var result = new LazyWrapper(this); + result.__dir__ = -1; + result.__filtered__ = true; + } else { + result = this.clone(); + result.__dir__ *= -1; + } + return result; + } + + /** + * Extracts the unwrapped value from its lazy wrapper. + * + * @private + * @name value + * @memberOf LazyWrapper + * @returns {*} Returns the unwrapped value. + */ + function lazyValue() { + var array = this.__wrapped__.value(), + dir = this.__dir__, + isArr = isArray(array), + isRight = dir < 0, + arrLength = isArr ? array.length : 0, + view = getView(0, arrLength, this.__views__), + start = view.start, + end = view.end, + length = end - start, + index = isRight ? end : (start - 1), + iteratees = this.__iteratees__, + iterLength = iteratees.length, + resIndex = 0, + takeCount = nativeMin(length, this.__takeCount__); + + if (!isArr || (!isRight && arrLength == length && takeCount == length)) { + return baseWrapperValue(array, this.__actions__); + } + var result = []; + + outer: + while (length-- && resIndex < takeCount) { + index += dir; + + var iterIndex = -1, + value = array[index]; + + while (++iterIndex < iterLength) { + var data = iteratees[iterIndex], + iteratee = data.iteratee, + type = data.type, + computed = iteratee(value); + + if (type == LAZY_MAP_FLAG) { + value = computed; + } else if (!computed) { + if (type == LAZY_FILTER_FLAG) { + continue outer; + } else { + break outer; + } + } + } + result[resIndex++] = value; + } + return result; + } + + // Ensure `LazyWrapper` is an instance of `baseLodash`. + LazyWrapper.prototype = baseCreate(baseLodash.prototype); + LazyWrapper.prototype.constructor = LazyWrapper; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ + function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; + } + + /** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty.call(data, key) ? data[key] : undefined; + } + + /** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); + } + + /** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ + function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; + } + + // Add methods to `Hash`. + Hash.prototype.clear = hashClear; + Hash.prototype['delete'] = hashDelete; + Hash.prototype.get = hashGet; + Hash.prototype.has = hashHas; + Hash.prototype.set = hashSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ + function listCacheClear() { + this.__data__ = []; + this.size = 0; + } + + /** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; + } + + /** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; + } + + /** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; + } + + /** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ + function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; + } + + // Add methods to `ListCache`. + ListCache.prototype.clear = listCacheClear; + ListCache.prototype['delete'] = listCacheDelete; + ListCache.prototype.get = listCacheGet; + ListCache.prototype.has = listCacheHas; + ListCache.prototype.set = listCacheSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ + function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map || ListCache), + 'string': new Hash + }; + } + + /** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function mapCacheGet(key) { + return getMapData(this, key).get(key); + } + + /** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function mapCacheHas(key) { + return getMapData(this, key).has(key); + } + + /** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ + function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; + } + + // Add methods to `MapCache`. + MapCache.prototype.clear = mapCacheClear; + MapCache.prototype['delete'] = mapCacheDelete; + MapCache.prototype.get = mapCacheGet; + MapCache.prototype.has = mapCacheHas; + MapCache.prototype.set = mapCacheSet; + + /*------------------------------------------------------------------------*/ + + /** + * + * Creates an array cache object to store unique values. + * + * @private + * @constructor + * @param {Array} [values] The values to cache. + */ + function SetCache(values) { + var index = -1, + length = values == null ? 0 : values.length; + + this.__data__ = new MapCache; + while (++index < length) { + this.add(values[index]); + } + } + + /** + * Adds `value` to the array cache. + * + * @private + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. + */ + function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED); + return this; + } + + /** + * Checks if `value` is in the array cache. + * + * @private + * @name has + * @memberOf SetCache + * @param {*} value The value to search for. + * @returns {number} Returns `true` if `value` is found, else `false`. + */ + function setCacheHas(value) { + return this.__data__.has(value); + } + + // Add methods to `SetCache`. + SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; + SetCache.prototype.has = setCacheHas; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a stack cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Stack(entries) { + var data = this.__data__ = new ListCache(entries); + this.size = data.size; + } + + /** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ + function stackClear() { + this.__data__ = new ListCache; + this.size = 0; + } + + /** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function stackDelete(key) { + var data = this.__data__, + result = data['delete'](key); + + this.size = data.size; + return result; + } + + /** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function stackGet(key) { + return this.__data__.get(key); + } + + /** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function stackHas(key) { + return this.__data__.has(key); + } + + /** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ + function stackSet(key, value) { + var data = this.__data__; + if (data instanceof ListCache) { + var pairs = data.__data__; + if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + this.size = ++data.size; + return this; + } + data = this.__data__ = new MapCache(pairs); + } + data.set(key, value); + this.size = data.size; + return this; + } + + // Add methods to `Stack`. + Stack.prototype.clear = stackClear; + Stack.prototype['delete'] = stackDelete; + Stack.prototype.get = stackGet; + Stack.prototype.has = stackHas; + Stack.prototype.set = stackSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ + function arrayLikeKeys(value, inherited) { + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; + + for (var key in value) { + if ((inherited || hasOwnProperty.call(value, key)) && + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { + result.push(key); + } + } + return result; + } + + /** + * A specialized version of `_.sample` for arrays. + * + * @private + * @param {Array} array The array to sample. + * @returns {*} Returns the random element. + */ + function arraySample(array) { + var length = array.length; + return length ? array[baseRandom(0, length - 1)] : undefined; + } + + /** + * A specialized version of `_.sampleSize` for arrays. + * + * @private + * @param {Array} array The array to sample. + * @param {number} n The number of elements to sample. + * @returns {Array} Returns the random elements. + */ + function arraySampleSize(array, n) { + return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length)); + } + + /** + * A specialized version of `_.shuffle` for arrays. + * + * @private + * @param {Array} array The array to shuffle. + * @returns {Array} Returns the new shuffled array. + */ + function arrayShuffle(array) { + return shuffleSelf(copyArray(array)); + } + + /** + * This function is like `assignValue` except that it doesn't assign + * `undefined` values. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignMergeValue(object, key, value) { + if ((value !== undefined && !eq(object[key], value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; + } + + /** + * Aggregates elements of `collection` on `accumulator` with keys transformed + * by `iteratee` and values set by `setter`. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform keys. + * @param {Object} accumulator The initial aggregated object. + * @returns {Function} Returns `accumulator`. + */ + function baseAggregator(collection, setter, iteratee, accumulator) { + baseEach(collection, function(value, key, collection) { + setter(accumulator, value, iteratee(value), collection); + }); + return accumulator; + } + + /** + * The base implementation of `_.assign` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssign(object, source) { + return object && copyObject(source, keys(source), object); + } + + /** + * The base implementation of `_.assignIn` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssignIn(object, source) { + return object && copyObject(source, keysIn(source), object); + } + + /** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } + } + + /** + * The base implementation of `_.at` without support for individual paths. + * + * @private + * @param {Object} object The object to iterate over. + * @param {string[]} paths The property paths to pick. + * @returns {Array} Returns the picked elements. + */ + function baseAt(object, paths) { + var index = -1, + length = paths.length, + result = Array(length), + skip = object == null; + + while (++index < length) { + result[index] = skip ? undefined : get(object, paths[index]); + } + return result; + } + + /** + * The base implementation of `_.clamp` which doesn't coerce arguments. + * + * @private + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + */ + function baseClamp(number, lower, upper) { + if (number === number) { + if (upper !== undefined) { + number = number <= upper ? number : upper; + } + if (lower !== undefined) { + number = number >= lower ? number : lower; + } + } + return number; + } + + /** + * The base implementation of `_.clone` and `_.cloneDeep` which tracks + * traversed objects. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} bitmask The bitmask flags. + * 1 - Deep clone + * 2 - Flatten inherited properties + * 4 - Clone symbols + * @param {Function} [customizer] The function to customize cloning. + * @param {string} [key] The key of `value`. + * @param {Object} [object] The parent object of `value`. + * @param {Object} [stack] Tracks traversed objects and their clone counterparts. + * @returns {*} Returns the cloned value. + */ + function baseClone(value, bitmask, customizer, key, object, stack) { + var result, + isDeep = bitmask & CLONE_DEEP_FLAG, + isFlat = bitmask & CLONE_FLAT_FLAG, + isFull = bitmask & CLONE_SYMBOLS_FLAG; + + if (customizer) { + result = object ? customizer(value, key, object, stack) : customizer(value); + } + if (result !== undefined) { + return result; + } + if (!isObject(value)) { + return value; + } + var isArr = isArray(value); + if (isArr) { + result = initCloneArray(value); + if (!isDeep) { + return copyArray(value, result); + } + } else { + var tag = getTag(value), + isFunc = tag == funcTag || tag == genTag; + + if (isBuffer(value)) { + return cloneBuffer(value, isDeep); + } + if (tag == objectTag || tag == argsTag || (isFunc && !object)) { + result = (isFlat || isFunc) ? {} : initCloneObject(value); + if (!isDeep) { + return isFlat + ? copySymbolsIn(value, baseAssignIn(result, value)) + : copySymbols(value, baseAssign(result, value)); + } + } else { + if (!cloneableTags[tag]) { + return object ? value : {}; + } + result = initCloneByTag(value, tag, isDeep); + } + } + // Check for circular references and return its corresponding clone. + stack || (stack = new Stack); + var stacked = stack.get(value); + if (stacked) { + return stacked; + } + stack.set(value, result); + + if (isSet(value)) { + value.forEach(function(subValue) { + result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack)); + }); + + return result; + } + + if (isMap(value)) { + value.forEach(function(subValue, key) { + result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + + return result; + } + + var keysFunc = isFull + ? (isFlat ? getAllKeysIn : getAllKeys) + : (isFlat ? keysIn : keys); + + var props = isArr ? undefined : keysFunc(value); + arrayEach(props || value, function(subValue, key) { + if (props) { + key = subValue; + subValue = value[key]; + } + // Recursively populate clone (susceptible to call stack limits). + assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + return result; + } + + /** + * The base implementation of `_.conforms` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property predicates to conform to. + * @returns {Function} Returns the new spec function. + */ + function baseConforms(source) { + var props = keys(source); + return function(object) { + return baseConformsTo(object, source, props); + }; + } + + /** + * The base implementation of `_.conformsTo` which accepts `props` to check. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property predicates to conform to. + * @returns {boolean} Returns `true` if `object` conforms, else `false`. + */ + function baseConformsTo(object, source, props) { + var length = props.length; + if (object == null) { + return !length; + } + object = Object(object); + while (length--) { + var key = props[length], + predicate = source[key], + value = object[key]; + + if ((value === undefined && !(key in object)) || !predicate(value)) { + return false; + } + } + return true; + } + + /** + * The base implementation of `_.delay` and `_.defer` which accepts `args` + * to provide to `func`. + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {Array} args The arguments to provide to `func`. + * @returns {number|Object} Returns the timer id or timeout object. + */ + function baseDelay(func, wait, args) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return setTimeout(function() { func.apply(undefined, args); }, wait); + } + + /** + * The base implementation of methods like `_.difference` without support + * for excluding multiple arrays or iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Array} values The values to exclude. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + */ + function baseDifference(array, values, iteratee, comparator) { + var index = -1, + includes = arrayIncludes, + isCommon = true, + length = array.length, + result = [], + valuesLength = values.length; + + if (!length) { + return result; + } + if (iteratee) { + values = arrayMap(values, baseUnary(iteratee)); + } + if (comparator) { + includes = arrayIncludesWith; + isCommon = false; + } + else if (values.length >= LARGE_ARRAY_SIZE) { + includes = cacheHas; + isCommon = false; + values = new SetCache(values); + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee == null ? value : iteratee(value); + + value = (comparator || value !== 0) ? value : 0; + if (isCommon && computed === computed) { + var valuesIndex = valuesLength; + while (valuesIndex--) { + if (values[valuesIndex] === computed) { + continue outer; + } + } + result.push(value); + } + else if (!includes(values, computed, comparator)) { + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.forEach` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + */ + var baseEach = createBaseEach(baseForOwn); + + /** + * The base implementation of `_.forEachRight` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + */ + var baseEachRight = createBaseEach(baseForOwnRight, true); + + /** + * The base implementation of `_.every` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false` + */ + function baseEvery(collection, predicate) { + var result = true; + baseEach(collection, function(value, index, collection) { + result = !!predicate(value, index, collection); + return result; + }); + return result; + } + + /** + * The base implementation of methods like `_.max` and `_.min` which accepts a + * `comparator` to determine the extremum value. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The iteratee invoked per iteration. + * @param {Function} comparator The comparator used to compare values. + * @returns {*} Returns the extremum value. + */ + function baseExtremum(array, iteratee, comparator) { + var index = -1, + length = array.length; + + while (++index < length) { + var value = array[index], + current = iteratee(value); + + if (current != null && (computed === undefined + ? (current === current && !isSymbol(current)) + : comparator(current, computed) + )) { + var computed = current, + result = value; + } + } + return result; + } + + /** + * The base implementation of `_.fill` without an iteratee call guard. + * + * @private + * @param {Array} array The array to fill. + * @param {*} value The value to fill `array` with. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns `array`. + */ + function baseFill(array, value, start, end) { + var length = array.length; + + start = toInteger(start); + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = (end === undefined || end > length) ? length : toInteger(end); + if (end < 0) { + end += length; + } + end = start > end ? 0 : toLength(end); + while (start < end) { + array[start++] = value; + } + return array; + } + + /** + * The base implementation of `_.filter` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function baseFilter(collection, predicate) { + var result = []; + baseEach(collection, function(value, index, collection) { + if (predicate(value, index, collection)) { + result.push(value); + } + }); + return result; + } + + /** + * The base implementation of `_.flatten` with support for restricting flattening. + * + * @private + * @param {Array} array The array to flatten. + * @param {number} depth The maximum recursion depth. + * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. + * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. + * @param {Array} [result=[]] The initial result value. + * @returns {Array} Returns the new flattened array. + */ + function baseFlatten(array, depth, predicate, isStrict, result) { + var index = -1, + length = array.length; + + predicate || (predicate = isFlattenable); + result || (result = []); + + while (++index < length) { + var value = array[index]; + if (depth > 0 && predicate(value)) { + if (depth > 1) { + // Recursively flatten arrays (susceptible to call stack limits). + baseFlatten(value, depth - 1, predicate, isStrict, result); + } else { + arrayPush(result, value); + } + } else if (!isStrict) { + result[result.length] = value; + } + } + return result; + } + + /** + * The base implementation of `baseForOwn` which iterates over `object` + * properties returned by `keysFunc` and invokes `iteratee` for each property. + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseFor = createBaseFor(); + + /** + * This function is like `baseFor` except that it iterates over properties + * in the opposite order. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseForRight = createBaseFor(true); + + /** + * The base implementation of `_.forOwn` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwn(object, iteratee) { + return object && baseFor(object, iteratee, keys); + } + + /** + * The base implementation of `_.forOwnRight` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwnRight(object, iteratee) { + return object && baseForRight(object, iteratee, keys); + } + + /** + * The base implementation of `_.functions` which creates an array of + * `object` function property names filtered from `props`. + * + * @private + * @param {Object} object The object to inspect. + * @param {Array} props The property names to filter. + * @returns {Array} Returns the function names. + */ + function baseFunctions(object, props) { + return arrayFilter(props, function(key) { + return isFunction(object[key]); + }); + } + + /** + * The base implementation of `_.get` without support for default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. + */ + function baseGet(object, path) { + path = castPath(path, object); + + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; + } + + /** + * The base implementation of `getAllKeys` and `getAllKeysIn` which uses + * `keysFunc` and `symbolsFunc` to get the enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Function} keysFunc The function to get the keys of `object`. + * @param {Function} symbolsFunc The function to get the symbols of `object`. + * @returns {Array} Returns the array of property names and symbols. + */ + function baseGetAllKeys(object, keysFunc, symbolsFunc) { + var result = keysFunc(object); + return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); + } + + /** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); + } + + /** + * The base implementation of `_.gt` which doesn't coerce arguments. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than `other`, + * else `false`. + */ + function baseGt(value, other) { + return value > other; + } + + /** + * The base implementation of `_.has` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHas(object, key) { + return object != null && hasOwnProperty.call(object, key); + } + + /** + * The base implementation of `_.hasIn` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHasIn(object, key) { + return object != null && key in Object(object); + } + + /** + * The base implementation of `_.inRange` which doesn't coerce arguments. + * + * @private + * @param {number} number The number to check. + * @param {number} start The start of the range. + * @param {number} end The end of the range. + * @returns {boolean} Returns `true` if `number` is in the range, else `false`. + */ + function baseInRange(number, start, end) { + return number >= nativeMin(start, end) && number < nativeMax(start, end); + } + + /** + * The base implementation of methods like `_.intersection`, without support + * for iteratee shorthands, that accepts an array of arrays to inspect. + * + * @private + * @param {Array} arrays The arrays to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of shared values. + */ + function baseIntersection(arrays, iteratee, comparator) { + var includes = comparator ? arrayIncludesWith : arrayIncludes, + length = arrays[0].length, + othLength = arrays.length, + othIndex = othLength, + caches = Array(othLength), + maxLength = Infinity, + result = []; + + while (othIndex--) { + var array = arrays[othIndex]; + if (othIndex && iteratee) { + array = arrayMap(array, baseUnary(iteratee)); + } + maxLength = nativeMin(array.length, maxLength); + caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) + ? new SetCache(othIndex && array) + : undefined; + } + array = arrays[0]; + + var index = -1, + seen = caches[0]; + + outer: + while (++index < length && result.length < maxLength) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + value = (comparator || value !== 0) ? value : 0; + if (!(seen + ? cacheHas(seen, computed) + : includes(result, computed, comparator) + )) { + othIndex = othLength; + while (--othIndex) { + var cache = caches[othIndex]; + if (!(cache + ? cacheHas(cache, computed) + : includes(arrays[othIndex], computed, comparator)) + ) { + continue outer; + } + } + if (seen) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.invert` and `_.invertBy` which inverts + * `object` with values transformed by `iteratee` and set by `setter`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform values. + * @param {Object} accumulator The initial inverted object. + * @returns {Function} Returns `accumulator`. + */ + function baseInverter(object, setter, iteratee, accumulator) { + baseForOwn(object, function(value, key, object) { + setter(accumulator, iteratee(value), key, object); + }); + return accumulator; + } + + /** + * The base implementation of `_.invoke` without support for individual + * method arguments. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {Array} args The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + */ + function baseInvoke(object, path, args) { + path = castPath(path, object); + object = parent(object, path); + var func = object == null ? object : object[toKey(last(path))]; + return func == null ? undefined : apply(func, object, args); + } + + /** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ + function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; + } + + /** + * The base implementation of `_.isArrayBuffer` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. + */ + function baseIsArrayBuffer(value) { + return isObjectLike(value) && baseGetTag(value) == arrayBufferTag; + } + + /** + * The base implementation of `_.isDate` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + */ + function baseIsDate(value) { + return isObjectLike(value) && baseGetTag(value) == dateTag; + } + + /** + * The base implementation of `_.isEqual` which supports partial comparisons + * and tracks traversed objects. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {boolean} bitmask The bitmask flags. + * 1 - Unordered comparison + * 2 - Partial comparison + * @param {Function} [customizer] The function to customize comparisons. + * @param {Object} [stack] Tracks traversed `value` and `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ + function baseIsEqual(value, other, bitmask, customizer, stack) { + if (value === other) { + return true; + } + if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); + } + + /** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} [stack] Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = objIsArr ? arrayTag : getTag(object), + othTag = othIsArr ? arrayTag : getTag(other); + + objTag = objTag == argsTag ? objectTag : objTag; + othTag = othTag == argsTag ? objectTag : othTag; + + var objIsObj = objTag == objectTag, + othIsObj = othTag == objectTag, + isSameTag = objTag == othTag; + + if (isSameTag && isBuffer(object)) { + if (!isBuffer(other)) { + return false; + } + objIsArr = true; + objIsObj = false; + } + if (isSameTag && !objIsObj) { + stack || (stack = new Stack); + return (objIsArr || isTypedArray(object)) + ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) + : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); + } + if (!(bitmask & COMPARE_PARTIAL_FLAG)) { + var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), + othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); + + if (objIsWrapped || othIsWrapped) { + var objUnwrapped = objIsWrapped ? object.value() : object, + othUnwrapped = othIsWrapped ? other.value() : other; + + stack || (stack = new Stack); + return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); + } + } + if (!isSameTag) { + return false; + } + stack || (stack = new Stack); + return equalObjects(object, other, bitmask, customizer, equalFunc, stack); + } + + /** + * The base implementation of `_.isMap` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + */ + function baseIsMap(value) { + return isObjectLike(value) && getTag(value) == mapTag; + } + + /** + * The base implementation of `_.isMatch` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Array} matchData The property names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ + function baseIsMatch(object, source, matchData, customizer) { + var index = matchData.length, + length = index, + noCustomizer = !customizer; + + if (object == null) { + return !length; + } + object = Object(object); + while (index--) { + var data = matchData[index]; + if ((noCustomizer && data[2]) + ? data[1] !== object[data[0]] + : !(data[0] in object) + ) { + return false; + } + } + while (++index < length) { + data = matchData[index]; + var key = data[0], + objValue = object[key], + srcValue = data[1]; + + if (noCustomizer && data[2]) { + if (objValue === undefined && !(key in object)) { + return false; + } + } else { + var stack = new Stack; + if (customizer) { + var result = customizer(objValue, srcValue, key, object, source, stack); + } + if (!(result === undefined + ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) + : result + )) { + return false; + } + } + } + return true; + } + + /** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ + function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); + } + + /** + * The base implementation of `_.isRegExp` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + */ + function baseIsRegExp(value) { + return isObjectLike(value) && baseGetTag(value) == regexpTag; + } + + /** + * The base implementation of `_.isSet` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + */ + function baseIsSet(value) { + return isObjectLike(value) && getTag(value) == setTag; + } + + /** + * The base implementation of `_.isTypedArray` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + */ + function baseIsTypedArray(value) { + return isObjectLike(value) && + isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; + } + + /** + * The base implementation of `_.iteratee`. + * + * @private + * @param {*} [value=_.identity] The value to convert to an iteratee. + * @returns {Function} Returns the iteratee. + */ + function baseIteratee(value) { + // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. + // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. + if (typeof value == 'function') { + return value; + } + if (value == null) { + return identity; + } + if (typeof value == 'object') { + return isArray(value) + ? baseMatchesProperty(value[0], value[1]) + : baseMatches(value); + } + return property(value); + } + + /** + * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeys(object) { + if (!isPrototype(object)) { + return nativeKeys(object); + } + var result = []; + for (var key in Object(object)) { + if (hasOwnProperty.call(object, key) && key != 'constructor') { + result.push(key); + } + } + return result; + } + + /** + * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeysIn(object) { + if (!isObject(object)) { + return nativeKeysIn(object); + } + var isProto = isPrototype(object), + result = []; + + for (var key in object) { + if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; + } + + /** + * The base implementation of `_.lt` which doesn't coerce arguments. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than `other`, + * else `false`. + */ + function baseLt(value, other) { + return value < other; + } + + /** + * The base implementation of `_.map` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function baseMap(collection, iteratee) { + var index = -1, + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value, key, collection) { + result[++index] = iteratee(value, key, collection); + }); + return result; + } + + /** + * The base implementation of `_.matches` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatches(source) { + var matchData = getMatchData(source); + if (matchData.length == 1 && matchData[0][2]) { + return matchesStrictComparable(matchData[0][0], matchData[0][1]); + } + return function(object) { + return object === source || baseIsMatch(object, source, matchData); + }; + } + + /** + * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. + * + * @private + * @param {string} path The path of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatchesProperty(path, srcValue) { + if (isKey(path) && isStrictComparable(srcValue)) { + return matchesStrictComparable(toKey(path), srcValue); + } + return function(object) { + var objValue = get(object, path); + return (objValue === undefined && objValue === srcValue) + ? hasIn(object, path) + : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG); + }; + } + + /** + * The base implementation of `_.merge` without support for multiple sources. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {number} srcIndex The index of `source`. + * @param {Function} [customizer] The function to customize merged values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMerge(object, source, srcIndex, customizer, stack) { + if (object === source) { + return; + } + baseFor(source, function(srcValue, key) { + if (isObject(srcValue)) { + stack || (stack = new Stack); + baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); + } + else { + var newValue = customizer + ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) + : undefined; + + if (newValue === undefined) { + newValue = srcValue; + } + assignMergeValue(object, key, newValue); + } + }, keysIn); + } + + /** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {number} srcIndex The index of `source`. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize assigned values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { + var objValue = safeGet(object, key), + srcValue = safeGet(source, key), + stacked = stack.get(srcValue); + + if (stacked) { + assignMergeValue(object, key, stacked); + return; + } + var newValue = customizer + ? customizer(objValue, srcValue, (key + ''), object, source, stack) + : undefined; + + var isCommon = newValue === undefined; + + if (isCommon) { + var isArr = isArray(srcValue), + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); + + newValue = srcValue; + if (isArr || isBuff || isTyped) { + if (isArray(objValue)) { + newValue = objValue; + } + else if (isArrayLikeObject(objValue)) { + newValue = copyArray(objValue); + } + else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } + else if (isTyped) { + isCommon = false; + newValue = cloneTypedArray(srcValue, true); + } + else { + newValue = []; + } + } + else if (isPlainObject(srcValue) || isArguments(srcValue)) { + newValue = objValue; + if (isArguments(objValue)) { + newValue = toPlainObject(objValue); + } + else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { + newValue = initCloneObject(srcValue); + } + } + else { + isCommon = false; + } + } + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, newValue); + mergeFunc(newValue, srcValue, srcIndex, customizer, stack); + stack['delete'](srcValue); + } + assignMergeValue(object, key, newValue); + } + + /** + * The base implementation of `_.nth` which doesn't coerce arguments. + * + * @private + * @param {Array} array The array to query. + * @param {number} n The index of the element to return. + * @returns {*} Returns the nth element of `array`. + */ + function baseNth(array, n) { + var length = array.length; + if (!length) { + return; + } + n += n < 0 ? length : 0; + return isIndex(n, length) ? array[n] : undefined; + } + + /** + * The base implementation of `_.orderBy` without param guards. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. + * @param {string[]} orders The sort orders of `iteratees`. + * @returns {Array} Returns the new sorted array. + */ + function baseOrderBy(collection, iteratees, orders) { + var index = -1; + iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee())); + + var result = baseMap(collection, function(value, key, collection) { + var criteria = arrayMap(iteratees, function(iteratee) { + return iteratee(value); + }); + return { 'criteria': criteria, 'index': ++index, 'value': value }; + }); + + return baseSortBy(result, function(object, other) { + return compareMultiple(object, other, orders); + }); + } + + /** + * The base implementation of `_.pick` without support for individual + * property identifiers. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @returns {Object} Returns the new object. + */ + function basePick(object, paths) { + return basePickBy(object, paths, function(value, path) { + return hasIn(object, path); + }); + } + + /** + * The base implementation of `_.pickBy` without support for iteratee shorthands. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @param {Function} predicate The function invoked per property. + * @returns {Object} Returns the new object. + */ + function basePickBy(object, paths, predicate) { + var index = -1, + length = paths.length, + result = {}; + + while (++index < length) { + var path = paths[index], + value = baseGet(object, path); + + if (predicate(value, path)) { + baseSet(result, castPath(path, object), value); + } + } + return result; + } + + /** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyDeep(path) { + return function(object) { + return baseGet(object, path); + }; + } + + /** + * The base implementation of `_.pullAllBy` without support for iteratee + * shorthands. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns `array`. + */ + function basePullAll(array, values, iteratee, comparator) { + var indexOf = comparator ? baseIndexOfWith : baseIndexOf, + index = -1, + length = values.length, + seen = array; + + if (array === values) { + values = copyArray(values); + } + if (iteratee) { + seen = arrayMap(array, baseUnary(iteratee)); + } + while (++index < length) { + var fromIndex = 0, + value = values[index], + computed = iteratee ? iteratee(value) : value; + + while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) { + if (seen !== array) { + splice.call(seen, fromIndex, 1); + } + splice.call(array, fromIndex, 1); + } + } + return array; + } + + /** + * The base implementation of `_.pullAt` without support for individual + * indexes or capturing the removed elements. + * + * @private + * @param {Array} array The array to modify. + * @param {number[]} indexes The indexes of elements to remove. + * @returns {Array} Returns `array`. + */ + function basePullAt(array, indexes) { + var length = array ? indexes.length : 0, + lastIndex = length - 1; + + while (length--) { + var index = indexes[length]; + if (length == lastIndex || index !== previous) { + var previous = index; + if (isIndex(index)) { + splice.call(array, index, 1); + } else { + baseUnset(array, index); + } + } + } + return array; + } + + /** + * The base implementation of `_.random` without support for returning + * floating-point numbers. + * + * @private + * @param {number} lower The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the random number. + */ + function baseRandom(lower, upper) { + return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); + } + + /** + * The base implementation of `_.range` and `_.rangeRight` which doesn't + * coerce arguments. + * + * @private + * @param {number} start The start of the range. + * @param {number} end The end of the range. + * @param {number} step The value to increment or decrement by. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the range of numbers. + */ + function baseRange(start, end, step, fromRight) { + var index = -1, + length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), + result = Array(length); + + while (length--) { + result[fromRight ? length : ++index] = start; + start += step; + } + return result; + } + + /** + * The base implementation of `_.repeat` which doesn't coerce arguments. + * + * @private + * @param {string} string The string to repeat. + * @param {number} n The number of times to repeat the string. + * @returns {string} Returns the repeated string. + */ + function baseRepeat(string, n) { + var result = ''; + if (!string || n < 1 || n > MAX_SAFE_INTEGER) { + return result; + } + // Leverage the exponentiation by squaring algorithm for a faster repeat. + // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. + do { + if (n % 2) { + result += string; + } + n = nativeFloor(n / 2); + if (n) { + string += string; + } + } while (n); + + return result; + } + + /** + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + */ + function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); + } + + /** + * The base implementation of `_.sample`. + * + * @private + * @param {Array|Object} collection The collection to sample. + * @returns {*} Returns the random element. + */ + function baseSample(collection) { + return arraySample(values(collection)); + } + + /** + * The base implementation of `_.sampleSize` without param guards. + * + * @private + * @param {Array|Object} collection The collection to sample. + * @param {number} n The number of elements to sample. + * @returns {Array} Returns the random elements. + */ + function baseSampleSize(collection, n) { + var array = values(collection); + return shuffleSelf(array, baseClamp(n, 0, array.length)); + } + + /** + * The base implementation of `_.set`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseSet(object, path, value, customizer) { + if (!isObject(object)) { + return object; + } + path = castPath(path, object); + + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; + + while (nested != null && ++index < length) { + var key = toKey(path[index]), + newValue = value; + + if (index != lastIndex) { + var objValue = nested[key]; + newValue = customizer ? customizer(objValue, key, nested) : undefined; + if (newValue === undefined) { + newValue = isObject(objValue) + ? objValue + : (isIndex(path[index + 1]) ? [] : {}); + } + } + assignValue(nested, key, newValue); + nested = nested[key]; + } + return object; + } + + /** + * The base implementation of `setData` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var baseSetData = !metaMap ? identity : function(func, data) { + metaMap.set(func, data); + return func; + }; + + /** + * The base implementation of `setToString` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); + }; + + /** + * The base implementation of `_.shuffle`. + * + * @private + * @param {Array|Object} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + */ + function baseShuffle(collection) { + return shuffleSelf(values(collection)); + } + + /** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = end > length ? length : end; + if (end < 0) { + end += length; + } + length = start > end ? 0 : ((end - start) >>> 0); + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; + } + + /** + * The base implementation of `_.some` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function baseSome(collection, predicate) { + var result; + + baseEach(collection, function(value, index, collection) { + result = predicate(value, index, collection); + return !result; + }); + return !!result; + } + + /** + * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which + * performs a binary search of `array` to determine the index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function baseSortedIndex(array, value, retHighest) { + var low = 0, + high = array == null ? low : array.length; + + if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { + while (low < high) { + var mid = (low + high) >>> 1, + computed = array[mid]; + + if (computed !== null && !isSymbol(computed) && + (retHighest ? (computed <= value) : (computed < value))) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + return baseSortedIndexBy(array, value, identity, retHighest); + } + + /** + * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy` + * which invokes `iteratee` for `value` and each element of `array` to compute + * their sort ranking. The iteratee is invoked with one argument; (value). + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} iteratee The iteratee invoked per element. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function baseSortedIndexBy(array, value, iteratee, retHighest) { + value = iteratee(value); + + var low = 0, + high = array == null ? 0 : array.length, + valIsNaN = value !== value, + valIsNull = value === null, + valIsSymbol = isSymbol(value), + valIsUndefined = value === undefined; + + while (low < high) { + var mid = nativeFloor((low + high) / 2), + computed = iteratee(array[mid]), + othIsDefined = computed !== undefined, + othIsNull = computed === null, + othIsReflexive = computed === computed, + othIsSymbol = isSymbol(computed); + + if (valIsNaN) { + var setLow = retHighest || othIsReflexive; + } else if (valIsUndefined) { + setLow = othIsReflexive && (retHighest || othIsDefined); + } else if (valIsNull) { + setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull); + } else if (valIsSymbol) { + setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol); + } else if (othIsNull || othIsSymbol) { + setLow = false; + } else { + setLow = retHighest ? (computed <= value) : (computed < value); + } + if (setLow) { + low = mid + 1; + } else { + high = mid; + } + } + return nativeMin(high, MAX_ARRAY_INDEX); + } + + /** + * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + */ + function baseSortedUniq(array, iteratee) { + var index = -1, + length = array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + if (!index || !eq(computed, seen)) { + var seen = computed; + result[resIndex++] = value === 0 ? 0 : value; + } + } + return result; + } + + /** + * The base implementation of `_.toNumber` which doesn't ensure correct + * conversions of binary, hexadecimal, or octal string values. + * + * @private + * @param {*} value The value to process. + * @returns {number} Returns the number. + */ + function baseToNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + return +value; + } + + /** + * The base implementation of `_.toString` which doesn't convert nullish + * values to empty strings. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ + function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value; + } + if (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } + if (isSymbol(value)) { + return symbolToString ? symbolToString.call(value) : ''; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * The base implementation of `_.uniqBy` without support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new duplicate free array. + */ + function baseUniq(array, iteratee, comparator) { + var index = -1, + includes = arrayIncludes, + length = array.length, + isCommon = true, + result = [], + seen = result; + + if (comparator) { + isCommon = false; + includes = arrayIncludesWith; + } + else if (length >= LARGE_ARRAY_SIZE) { + var set = iteratee ? null : createSet(array); + if (set) { + return setToArray(set); + } + isCommon = false; + includes = cacheHas; + seen = new SetCache; + } + else { + seen = iteratee ? [] : result; + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + value = (comparator || value !== 0) ? value : 0; + if (isCommon && computed === computed) { + var seenIndex = seen.length; + while (seenIndex--) { + if (seen[seenIndex] === computed) { + continue outer; + } + } + if (iteratee) { + seen.push(computed); + } + result.push(value); + } + else if (!includes(seen, computed, comparator)) { + if (seen !== result) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.unset`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The property path to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + */ + function baseUnset(object, path) { + path = castPath(path, object); + object = parent(object, path); + return object == null || delete object[toKey(last(path))]; + } + + /** + * The base implementation of `_.update`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to update. + * @param {Function} updater The function to produce the updated value. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseUpdate(object, path, updater, customizer) { + return baseSet(object, path, updater(baseGet(object, path)), customizer); + } + + /** + * The base implementation of methods like `_.dropWhile` and `_.takeWhile` + * without support for iteratee shorthands. + * + * @private + * @param {Array} array The array to query. + * @param {Function} predicate The function invoked per iteration. + * @param {boolean} [isDrop] Specify dropping elements instead of taking them. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the slice of `array`. + */ + function baseWhile(array, predicate, isDrop, fromRight) { + var length = array.length, + index = fromRight ? length : -1; + + while ((fromRight ? index-- : ++index < length) && + predicate(array[index], index, array)) {} + + return isDrop + ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) + : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); + } + + /** + * The base implementation of `wrapperValue` which returns the result of + * performing a sequence of actions on the unwrapped `value`, where each + * successive action is supplied the return value of the previous. + * + * @private + * @param {*} value The unwrapped value. + * @param {Array} actions Actions to perform to resolve the unwrapped value. + * @returns {*} Returns the resolved value. + */ + function baseWrapperValue(value, actions) { + var result = value; + if (result instanceof LazyWrapper) { + result = result.value(); + } + return arrayReduce(actions, function(result, action) { + return action.func.apply(action.thisArg, arrayPush([result], action.args)); + }, result); + } + + /** + * The base implementation of methods like `_.xor`, without support for + * iteratee shorthands, that accepts an array of arrays to inspect. + * + * @private + * @param {Array} arrays The arrays to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of values. + */ + function baseXor(arrays, iteratee, comparator) { + var length = arrays.length; + if (length < 2) { + return length ? baseUniq(arrays[0]) : []; + } + var index = -1, + result = Array(length); + + while (++index < length) { + var array = arrays[index], + othIndex = -1; + + while (++othIndex < length) { + if (othIndex != index) { + result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator); + } + } + } + return baseUniq(baseFlatten(result, 1), iteratee, comparator); + } + + /** + * This base implementation of `_.zipObject` which assigns values using `assignFunc`. + * + * @private + * @param {Array} props The property identifiers. + * @param {Array} values The property values. + * @param {Function} assignFunc The function to assign values. + * @returns {Object} Returns the new object. + */ + function baseZipObject(props, values, assignFunc) { + var index = -1, + length = props.length, + valsLength = values.length, + result = {}; + + while (++index < length) { + var value = index < valsLength ? values[index] : undefined; + assignFunc(result, props[index], value); + } + return result; + } + + /** + * Casts `value` to an empty array if it's not an array like object. + * + * @private + * @param {*} value The value to inspect. + * @returns {Array|Object} Returns the cast array-like object. + */ + function castArrayLikeObject(value) { + return isArrayLikeObject(value) ? value : []; + } + + /** + * Casts `value` to `identity` if it's not a function. + * + * @private + * @param {*} value The value to inspect. + * @returns {Function} Returns cast function. + */ + function castFunction(value) { + return typeof value == 'function' ? value : identity; + } + + /** + * Casts `value` to a path array if it's not one. + * + * @private + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. + */ + function castPath(value, object) { + if (isArray(value)) { + return value; + } + return isKey(value, object) ? [value] : stringToPath(toString(value)); + } + + /** + * A `baseRest` alias which can be replaced with `identity` by module + * replacement plugins. + * + * @private + * @type {Function} + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. + */ + var castRest = baseRest; + + /** + * Casts `array` to a slice if it's needed. + * + * @private + * @param {Array} array The array to inspect. + * @param {number} start The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the cast slice. + */ + function castSlice(array, start, end) { + var length = array.length; + end = end === undefined ? length : end; + return (!start && end >= length) ? array : baseSlice(array, start, end); + } + + /** + * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout). + * + * @private + * @param {number|Object} id The timer id or timeout object of the timer to clear. + */ + var clearTimeout = ctxClearTimeout || function(id) { + return root.clearTimeout(id); + }; + + /** + * Creates a clone of `buffer`. + * + * @private + * @param {Buffer} buffer The buffer to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Buffer} Returns the cloned buffer. + */ + function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); + } + var length = buffer.length, + result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); + + buffer.copy(result); + return result; + } + + /** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ + function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + return result; + } + + /** + * Creates a clone of `dataView`. + * + * @private + * @param {Object} dataView The data view to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned data view. + */ + function cloneDataView(dataView, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; + return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); + } + + /** + * Creates a clone of `regexp`. + * + * @private + * @param {Object} regexp The regexp to clone. + * @returns {Object} Returns the cloned regexp. + */ + function cloneRegExp(regexp) { + var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); + result.lastIndex = regexp.lastIndex; + return result; + } + + /** + * Creates a clone of the `symbol` object. + * + * @private + * @param {Object} symbol The symbol object to clone. + * @returns {Object} Returns the cloned symbol object. + */ + function cloneSymbol(symbol) { + return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; + } + + /** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ + function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); + } + + /** + * Compares values to sort them in ascending order. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {number} Returns the sort order indicator for `value`. + */ + function compareAscending(value, other) { + if (value !== other) { + var valIsDefined = value !== undefined, + valIsNull = value === null, + valIsReflexive = value === value, + valIsSymbol = isSymbol(value); + + var othIsDefined = other !== undefined, + othIsNull = other === null, + othIsReflexive = other === other, + othIsSymbol = isSymbol(other); + + if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || + (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || + (valIsNull && othIsDefined && othIsReflexive) || + (!valIsDefined && othIsReflexive) || + !valIsReflexive) { + return 1; + } + if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || + (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || + (othIsNull && valIsDefined && valIsReflexive) || + (!othIsDefined && valIsReflexive) || + !othIsReflexive) { + return -1; + } + } + return 0; + } + + /** + * Used by `_.orderBy` to compare multiple properties of a value to another + * and stable sort them. + * + * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, + * specify an order of "desc" for descending or "asc" for ascending sort order + * of corresponding values. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {boolean[]|string[]} orders The order to sort by for each property. + * @returns {number} Returns the sort order indicator for `object`. + */ + function compareMultiple(object, other, orders) { + var index = -1, + objCriteria = object.criteria, + othCriteria = other.criteria, + length = objCriteria.length, + ordersLength = orders.length; + + while (++index < length) { + var result = compareAscending(objCriteria[index], othCriteria[index]); + if (result) { + if (index >= ordersLength) { + return result; + } + var order = orders[index]; + return result * (order == 'desc' ? -1 : 1); + } + } + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to provide the same value for + // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 + // for more details. + // + // This also ensures a stable sort in V8 and other engines. + // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. + return object.index - other.index; + } + + /** + * Creates an array that is the composition of partially applied arguments, + * placeholders, and provided arguments into a single array of arguments. + * + * @private + * @param {Array} args The provided arguments. + * @param {Array} partials The arguments to prepend to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @params {boolean} [isCurried] Specify composing for a curried function. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgs(args, partials, holders, isCurried) { + var argsIndex = -1, + argsLength = args.length, + holdersLength = holders.length, + leftIndex = -1, + leftLength = partials.length, + rangeLength = nativeMax(argsLength - holdersLength, 0), + result = Array(leftLength + rangeLength), + isUncurried = !isCurried; + + while (++leftIndex < leftLength) { + result[leftIndex] = partials[leftIndex]; + } + while (++argsIndex < holdersLength) { + if (isUncurried || argsIndex < argsLength) { + result[holders[argsIndex]] = args[argsIndex]; + } + } + while (rangeLength--) { + result[leftIndex++] = args[argsIndex++]; + } + return result; + } + + /** + * This function is like `composeArgs` except that the arguments composition + * is tailored for `_.partialRight`. + * + * @private + * @param {Array} args The provided arguments. + * @param {Array} partials The arguments to append to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @params {boolean} [isCurried] Specify composing for a curried function. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgsRight(args, partials, holders, isCurried) { + var argsIndex = -1, + argsLength = args.length, + holdersIndex = -1, + holdersLength = holders.length, + rightIndex = -1, + rightLength = partials.length, + rangeLength = nativeMax(argsLength - holdersLength, 0), + result = Array(rangeLength + rightLength), + isUncurried = !isCurried; + + while (++argsIndex < rangeLength) { + result[argsIndex] = args[argsIndex]; + } + var offset = argsIndex; + while (++rightIndex < rightLength) { + result[offset + rightIndex] = partials[rightIndex]; + } + while (++holdersIndex < holdersLength) { + if (isUncurried || argsIndex < argsLength) { + result[offset + holders[holdersIndex]] = args[argsIndex++]; + } + } + return result; + } + + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } + + /** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ + function copyObject(source, props, object, customizer) { + var isNew = !object; + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; + + if (newValue === undefined) { + newValue = source[key]; + } + if (isNew) { + baseAssignValue(object, key, newValue); + } else { + assignValue(object, key, newValue); + } + } + return object; + } + + /** + * Copies own symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ + function copySymbols(source, object) { + return copyObject(source, getSymbols(source), object); + } + + /** + * Copies own and inherited symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ + function copySymbolsIn(source, object) { + return copyObject(source, getSymbolsIn(source), object); + } + + /** + * Creates a function like `_.groupBy`. + * + * @private + * @param {Function} setter The function to set accumulator values. + * @param {Function} [initializer] The accumulator object initializer. + * @returns {Function} Returns the new aggregator function. + */ + function createAggregator(setter, initializer) { + return function(collection, iteratee) { + var func = isArray(collection) ? arrayAggregator : baseAggregator, + accumulator = initializer ? initializer() : {}; + + return func(collection, setter, getIteratee(iteratee, 2), accumulator); + }; + } + + /** + * Creates a function like `_.assign`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ + function createAssigner(assigner) { + return baseRest(function(object, sources) { + var index = -1, + length = sources.length, + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); + } + + /** + * Creates a `baseEach` or `baseEachRight` function. + * + * @private + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseEach(eachFunc, fromRight) { + return function(collection, iteratee) { + if (collection == null) { + return collection; + } + if (!isArrayLike(collection)) { + return eachFunc(collection, iteratee); + } + var length = collection.length, + index = fromRight ? length : -1, + iterable = Object(collection); + + while ((fromRight ? index-- : ++index < length)) { + if (iteratee(iterable[index], index, iterable) === false) { + break; + } + } + return collection; + }; + } + + /** + * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; + } + + /** + * Creates a function that wraps `func` to invoke it with the optional `this` + * binding of `thisArg`. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createBind(func, bitmask, thisArg) { + var isBind = bitmask & WRAP_BIND_FLAG, + Ctor = createCtor(func); + + function wrapper() { + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return fn.apply(isBind ? thisArg : this, arguments); + } + return wrapper; + } + + /** + * Creates a function like `_.lowerFirst`. + * + * @private + * @param {string} methodName The name of the `String` case method to use. + * @returns {Function} Returns the new case function. + */ + function createCaseFirst(methodName) { + return function(string) { + string = toString(string); + + var strSymbols = hasUnicode(string) + ? stringToArray(string) + : undefined; + + var chr = strSymbols + ? strSymbols[0] + : string.charAt(0); + + var trailing = strSymbols + ? castSlice(strSymbols, 1).join('') + : string.slice(1); + + return chr[methodName]() + trailing; + }; + } + + /** + * Creates a function like `_.camelCase`. + * + * @private + * @param {Function} callback The function to combine each word. + * @returns {Function} Returns the new compounder function. + */ + function createCompounder(callback) { + return function(string) { + return arrayReduce(words(deburr(string).replace(reApos, '')), callback, ''); + }; + } + + /** + * Creates a function that produces an instance of `Ctor` regardless of + * whether it was invoked as part of a `new` expression or by `call` or `apply`. + * + * @private + * @param {Function} Ctor The constructor to wrap. + * @returns {Function} Returns the new wrapped function. + */ + function createCtor(Ctor) { + return function() { + // Use a `switch` statement to work with class constructors. See + // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist + // for more details. + var args = arguments; + switch (args.length) { + case 0: return new Ctor; + case 1: return new Ctor(args[0]); + case 2: return new Ctor(args[0], args[1]); + case 3: return new Ctor(args[0], args[1], args[2]); + case 4: return new Ctor(args[0], args[1], args[2], args[3]); + case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); + case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + } + var thisBinding = baseCreate(Ctor.prototype), + result = Ctor.apply(thisBinding, args); + + // Mimic the constructor's `return` behavior. + // See https://es5.github.io/#x13.2.2 for more details. + return isObject(result) ? result : thisBinding; + }; + } + + /** + * Creates a function that wraps `func` to enable currying. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {number} arity The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createCurry(func, bitmask, arity) { + var Ctor = createCtor(func); + + function wrapper() { + var length = arguments.length, + args = Array(length), + index = length, + placeholder = getHolder(wrapper); + + while (index--) { + args[index] = arguments[index]; + } + var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) + ? [] + : replaceHolders(args, placeholder); + + length -= holders.length; + if (length < arity) { + return createRecurry( + func, bitmask, createHybrid, wrapper.placeholder, undefined, + args, holders, undefined, undefined, arity - length); + } + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return apply(fn, this, args); + } + return wrapper; + } + + /** + * Creates a `_.find` or `_.findLast` function. + * + * @private + * @param {Function} findIndexFunc The function to find the collection index. + * @returns {Function} Returns the new find function. + */ + function createFind(findIndexFunc) { + return function(collection, predicate, fromIndex) { + var iterable = Object(collection); + if (!isArrayLike(collection)) { + var iteratee = getIteratee(predicate, 3); + collection = keys(collection); + predicate = function(key) { return iteratee(iterable[key], key, iterable); }; + } + var index = findIndexFunc(collection, predicate, fromIndex); + return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; + }; + } + + /** + * Creates a `_.flow` or `_.flowRight` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new flow function. + */ + function createFlow(fromRight) { + return flatRest(function(funcs) { + var length = funcs.length, + index = length, + prereq = LodashWrapper.prototype.thru; + + if (fromRight) { + funcs.reverse(); + } + while (index--) { + var func = funcs[index]; + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (prereq && !wrapper && getFuncName(func) == 'wrapper') { + var wrapper = new LodashWrapper([], true); + } + } + index = wrapper ? index : length; + while (++index < length) { + func = funcs[index]; + + var funcName = getFuncName(func), + data = funcName == 'wrapper' ? getData(func) : undefined; + + if (data && isLaziable(data[0]) && + data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) && + !data[4].length && data[9] == 1 + ) { + wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); + } else { + wrapper = (func.length == 1 && isLaziable(func)) + ? wrapper[funcName]() + : wrapper.thru(func); + } + } + return function() { + var args = arguments, + value = args[0]; + + if (wrapper && args.length == 1 && isArray(value)) { + return wrapper.plant(value).value(); + } + var index = 0, + result = length ? funcs[index].apply(this, args) : value; + + while (++index < length) { + result = funcs[index].call(this, result); + } + return result; + }; + }); + } + + /** + * Creates a function that wraps `func` to invoke it with optional `this` + * binding of `thisArg`, partial application, and currying. + * + * @private + * @param {Function|string} func The function or method name to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to + * the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [partialsRight] The arguments to append to those provided + * to the new function. + * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { + var isAry = bitmask & WRAP_ARY_FLAG, + isBind = bitmask & WRAP_BIND_FLAG, + isBindKey = bitmask & WRAP_BIND_KEY_FLAG, + isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), + isFlip = bitmask & WRAP_FLIP_FLAG, + Ctor = isBindKey ? undefined : createCtor(func); + + function wrapper() { + var length = arguments.length, + args = Array(length), + index = length; + + while (index--) { + args[index] = arguments[index]; + } + if (isCurried) { + var placeholder = getHolder(wrapper), + holdersCount = countHolders(args, placeholder); + } + if (partials) { + args = composeArgs(args, partials, holders, isCurried); + } + if (partialsRight) { + args = composeArgsRight(args, partialsRight, holdersRight, isCurried); + } + length -= holdersCount; + if (isCurried && length < arity) { + var newHolders = replaceHolders(args, placeholder); + return createRecurry( + func, bitmask, createHybrid, wrapper.placeholder, thisArg, + args, newHolders, argPos, ary, arity - length + ); + } + var thisBinding = isBind ? thisArg : this, + fn = isBindKey ? thisBinding[func] : func; + + length = args.length; + if (argPos) { + args = reorder(args, argPos); + } else if (isFlip && length > 1) { + args.reverse(); + } + if (isAry && ary < length) { + args.length = ary; + } + if (this && this !== root && this instanceof wrapper) { + fn = Ctor || createCtor(fn); + } + return fn.apply(thisBinding, args); + } + return wrapper; + } + + /** + * Creates a function like `_.invertBy`. + * + * @private + * @param {Function} setter The function to set accumulator values. + * @param {Function} toIteratee The function to resolve iteratees. + * @returns {Function} Returns the new inverter function. + */ + function createInverter(setter, toIteratee) { + return function(object, iteratee) { + return baseInverter(object, setter, toIteratee(iteratee), {}); + }; + } + + /** + * Creates a function that performs a mathematical operation on two values. + * + * @private + * @param {Function} operator The function to perform the operation. + * @param {number} [defaultValue] The value used for `undefined` arguments. + * @returns {Function} Returns the new mathematical operation function. + */ + function createMathOperation(operator, defaultValue) { + return function(value, other) { + var result; + if (value === undefined && other === undefined) { + return defaultValue; + } + if (value !== undefined) { + result = value; + } + if (other !== undefined) { + if (result === undefined) { + return other; + } + if (typeof value == 'string' || typeof other == 'string') { + value = baseToString(value); + other = baseToString(other); + } else { + value = baseToNumber(value); + other = baseToNumber(other); + } + result = operator(value, other); + } + return result; + }; + } + + /** + * Creates a function like `_.over`. + * + * @private + * @param {Function} arrayFunc The function to iterate over iteratees. + * @returns {Function} Returns the new over function. + */ + function createOver(arrayFunc) { + return flatRest(function(iteratees) { + iteratees = arrayMap(iteratees, baseUnary(getIteratee())); + return baseRest(function(args) { + var thisArg = this; + return arrayFunc(iteratees, function(iteratee) { + return apply(iteratee, thisArg, args); + }); + }); + }); + } + + /** + * Creates the padding for `string` based on `length`. The `chars` string + * is truncated if the number of characters exceeds `length`. + * + * @private + * @param {number} length The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padding for `string`. + */ + function createPadding(length, chars) { + chars = chars === undefined ? ' ' : baseToString(chars); + + var charsLength = chars.length; + if (charsLength < 2) { + return charsLength ? baseRepeat(chars, length) : chars; + } + var result = baseRepeat(chars, nativeCeil(length / stringSize(chars))); + return hasUnicode(chars) + ? castSlice(stringToArray(result), 0, length).join('') + : result.slice(0, length); + } + + /** + * Creates a function that wraps `func` to invoke it with the `this` binding + * of `thisArg` and `partials` prepended to the arguments it receives. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} partials The arguments to prepend to those provided to + * the new function. + * @returns {Function} Returns the new wrapped function. + */ + function createPartial(func, bitmask, thisArg, partials) { + var isBind = bitmask & WRAP_BIND_FLAG, + Ctor = createCtor(func); + + function wrapper() { + var argsIndex = -1, + argsLength = arguments.length, + leftIndex = -1, + leftLength = partials.length, + args = Array(leftLength + argsLength), + fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + + while (++leftIndex < leftLength) { + args[leftIndex] = partials[leftIndex]; + } + while (argsLength--) { + args[leftIndex++] = arguments[++argsIndex]; + } + return apply(fn, isBind ? thisArg : this, args); + } + return wrapper; + } + + /** + * Creates a `_.range` or `_.rangeRight` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new range function. + */ + function createRange(fromRight) { + return function(start, end, step) { + if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { + end = step = undefined; + } + // Ensure the sign of `-0` is preserved. + start = toFinite(start); + if (end === undefined) { + end = start; + start = 0; + } else { + end = toFinite(end); + } + step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); + return baseRange(start, end, step, fromRight); + }; + } + + /** + * Creates a function that performs a relational operation on two values. + * + * @private + * @param {Function} operator The function to perform the operation. + * @returns {Function} Returns the new relational operation function. + */ + function createRelationalOperation(operator) { + return function(value, other) { + if (!(typeof value == 'string' && typeof other == 'string')) { + value = toNumber(value); + other = toNumber(other); + } + return operator(value, other); + }; + } + + /** + * Creates a function that wraps `func` to continue currying. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {Function} wrapFunc The function to create the `func` wrapper. + * @param {*} placeholder The placeholder value. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to + * the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { + var isCurry = bitmask & WRAP_CURRY_FLAG, + newHolders = isCurry ? holders : undefined, + newHoldersRight = isCurry ? undefined : holders, + newPartials = isCurry ? partials : undefined, + newPartialsRight = isCurry ? undefined : partials; + + bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG); + bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG); + + if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) { + bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG); + } + var newData = [ + func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, + newHoldersRight, argPos, ary, arity + ]; + + var result = wrapFunc.apply(undefined, newData); + if (isLaziable(func)) { + setData(result, newData); + } + result.placeholder = placeholder; + return setWrapToString(result, func, bitmask); + } + + /** + * Creates a function like `_.round`. + * + * @private + * @param {string} methodName The name of the `Math` method to use when rounding. + * @returns {Function} Returns the new round function. + */ + function createRound(methodName) { + var func = Math[methodName]; + return function(number, precision) { + number = toNumber(number); + precision = precision == null ? 0 : nativeMin(toInteger(precision), 292); + if (precision) { + // Shift with exponential notation to avoid floating-point issues. + // See [MDN](https://mdn.io/round#Examples) for more details. + var pair = (toString(number) + 'e').split('e'), + value = func(pair[0] + 'e' + (+pair[1] + precision)); + + pair = (toString(value) + 'e').split('e'); + return +(pair[0] + 'e' + (+pair[1] - precision)); + } + return func(number); + }; + } + + /** + * Creates a set object of `values`. + * + * @private + * @param {Array} values The values to add to the set. + * @returns {Object} Returns the new set. + */ + var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) { + return new Set(values); + }; + + /** + * Creates a `_.toPairs` or `_.toPairsIn` function. + * + * @private + * @param {Function} keysFunc The function to get the keys of a given object. + * @returns {Function} Returns the new pairs function. + */ + function createToPairs(keysFunc) { + return function(object) { + var tag = getTag(object); + if (tag == mapTag) { + return mapToArray(object); + } + if (tag == setTag) { + return setToPairs(object); + } + return baseToPairs(object, keysFunc(object)); + }; + } + + /** + * Creates a function that either curries or invokes `func` with optional + * `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to wrap. + * @param {number} bitmask The bitmask flags. + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` or `_.curryRight` of a bound function + * 8 - `_.curry` + * 16 - `_.curryRight` + * 32 - `_.partial` + * 64 - `_.partialRight` + * 128 - `_.rearg` + * 256 - `_.ary` + * 512 - `_.flip` + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to be partially applied. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { + var isBindKey = bitmask & WRAP_BIND_KEY_FLAG; + if (!isBindKey && typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = partials ? partials.length : 0; + if (!length) { + bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG); + partials = holders = undefined; + } + ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); + arity = arity === undefined ? arity : toInteger(arity); + length -= holders ? holders.length : 0; + + if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) { + var partialsRight = partials, + holdersRight = holders; + + partials = holders = undefined; + } + var data = isBindKey ? undefined : getData(func); + + var newData = [ + func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, + argPos, ary, arity + ]; + + if (data) { + mergeData(newData, data); + } + func = newData[0]; + bitmask = newData[1]; + thisArg = newData[2]; + partials = newData[3]; + holders = newData[4]; + arity = newData[9] = newData[9] === undefined + ? (isBindKey ? 0 : func.length) + : nativeMax(newData[9] - length, 0); + + if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) { + bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG); + } + if (!bitmask || bitmask == WRAP_BIND_FLAG) { + var result = createBind(func, bitmask, thisArg); + } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) { + result = createCurry(func, bitmask, arity); + } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) { + result = createPartial(func, bitmask, thisArg, partials); + } else { + result = createHybrid.apply(undefined, newData); + } + var setter = data ? baseSetData : setData; + return setWrapToString(setter(result, newData), func, bitmask); + } + + /** + * Used by `_.defaults` to customize its `_.assignIn` use to assign properties + * of source objects to the destination object for all destination properties + * that resolve to `undefined`. + * + * @private + * @param {*} objValue The destination value. + * @param {*} srcValue The source value. + * @param {string} key The key of the property to assign. + * @param {Object} object The parent object of `objValue`. + * @returns {*} Returns the value to assign. + */ + function customDefaultsAssignIn(objValue, srcValue, key, object) { + if (objValue === undefined || + (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { + return srcValue; + } + return objValue; + } + + /** + * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source + * objects into destination objects that are passed thru. + * + * @private + * @param {*} objValue The destination value. + * @param {*} srcValue The source value. + * @param {string} key The key of the property to merge. + * @param {Object} object The parent object of `objValue`. + * @param {Object} source The parent object of `srcValue`. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + * @returns {*} Returns the value to assign. + */ + function customDefaultsMerge(objValue, srcValue, key, object, source, stack) { + if (isObject(objValue) && isObject(srcValue)) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, objValue); + baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack); + stack['delete'](srcValue); + } + return objValue; + } + + /** + * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain + * objects. + * + * @private + * @param {*} value The value to inspect. + * @param {string} key The key of the property to inspect. + * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`. + */ + function customOmitClone(value) { + return isPlainObject(value) ? undefined : value; + } + + /** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `array` and `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ + function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isPartial && othLength > arrLength)) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(array); + if (stacked && stack.get(other)) { + return stacked == other; + } + var index = -1, + result = true, + seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; + + stack.set(array, other); + stack.set(other, array); + + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, arrValue, index, other, array, stack) + : customizer(arrValue, othValue, index, array, other, stack); + } + if (compared !== undefined) { + if (compared) { + continue; + } + result = false; + break; + } + // Recursively compare arrays (susceptible to call stack limits). + if (seen) { + if (!arraySome(other, function(othValue, othIndex) { + if (!cacheHas(seen, othIndex) && + (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { + return seen.push(othIndex); + } + })) { + result = false; + break; + } + } else if (!( + arrValue === othValue || + equalFunc(arrValue, othValue, bitmask, customizer, stack) + )) { + result = false; + break; + } + } + stack['delete'](array); + stack['delete'](other); + return result; + } + + /** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { + switch (tag) { + case dataViewTag: + if ((object.byteLength != other.byteLength) || + (object.byteOffset != other.byteOffset)) { + return false; + } + object = object.buffer; + other = other.buffer; + + case arrayBufferTag: + if ((object.byteLength != other.byteLength) || + !equalFunc(new Uint8Array(object), new Uint8Array(other))) { + return false; + } + return true; + + case boolTag: + case dateTag: + case numberTag: + // Coerce booleans to `1` or `0` and dates to milliseconds. + // Invalid dates are coerced to `NaN`. + return eq(+object, +other); + + case errorTag: + return object.name == other.name && object.message == other.message; + + case regexpTag: + case stringTag: + // Coerce regexes to strings and treat strings, primitives and objects, + // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring + // for more details. + return object == (other + ''); + + case mapTag: + var convert = mapToArray; + + case setTag: + var isPartial = bitmask & COMPARE_PARTIAL_FLAG; + convert || (convert = setToArray); + + if (object.size != other.size && !isPartial) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked) { + return stacked == other; + } + bitmask |= COMPARE_UNORDERED_FLAG; + + // Recursively compare objects (susceptible to call stack limits). + stack.set(object, other); + var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); + stack['delete'](object); + return result; + + case symbolTag: + if (symbolValueOf) { + return symbolValueOf.call(object) == symbolValueOf.call(other); + } + } + return false; + } + + /** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + objProps = getAllKeys(object), + objLength = objProps.length, + othProps = getAllKeys(other), + othLength = othProps.length; + + if (objLength != othLength && !isPartial) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { + return false; + } + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked && stack.get(other)) { + return stacked == other; + } + var result = true; + stack.set(object, other); + stack.set(other, object); + + var skipCtor = isPartial; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, objValue, key, other, object, stack) + : customizer(objValue, othValue, key, object, other, stack); + } + // Recursively compare objects (susceptible to call stack limits). + if (!(compared === undefined + ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) + : compared + )) { + result = false; + break; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (result && !skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && + typeof othCtor == 'function' && othCtor instanceof othCtor)) { + result = false; + } + } + stack['delete'](object); + stack['delete'](other); + return result; + } + + /** + * A specialized version of `baseRest` which flattens the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. + */ + function flatRest(func) { + return setToString(overRest(func, undefined, flatten), func + ''); + } + + /** + * Creates an array of own enumerable property names and symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeys(object) { + return baseGetAllKeys(object, keys, getSymbols); + } + + /** + * Creates an array of own and inherited enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeysIn(object) { + return baseGetAllKeys(object, keysIn, getSymbolsIn); + } + + /** + * Gets metadata for `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {*} Returns the metadata for `func`. + */ + var getData = !metaMap ? noop : function(func) { + return metaMap.get(func); + }; + + /** + * Gets the name of `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {string} Returns the function name. + */ + function getFuncName(func) { + var result = (func.name + ''), + array = realNames[result], + length = hasOwnProperty.call(realNames, result) ? array.length : 0; + + while (length--) { + var data = array[length], + otherFunc = data.func; + if (otherFunc == null || otherFunc == func) { + return data.name; + } + } + return result; + } + + /** + * Gets the argument placeholder value for `func`. + * + * @private + * @param {Function} func The function to inspect. + * @returns {*} Returns the placeholder value. + */ + function getHolder(func) { + var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; + return object.placeholder; + } + + /** + * Gets the appropriate "iteratee" function. If `_.iteratee` is customized, + * this function returns the custom method, otherwise it returns `baseIteratee`. + * If arguments are provided, the chosen function is invoked with them and + * its result is returned. + * + * @private + * @param {*} [value] The value to convert to an iteratee. + * @param {number} [arity] The arity of the created iteratee. + * @returns {Function} Returns the chosen function or its result. + */ + function getIteratee() { + var result = lodash.iteratee || iteratee; + result = result === iteratee ? baseIteratee : result; + return arguments.length ? result(arguments[0], arguments[1]) : result; + } + + /** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ + function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; + } + + /** + * Gets the property names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ + function getMatchData(object) { + var result = keys(object), + length = result.length; + + while (length--) { + var key = result[length], + value = object[key]; + + result[length] = [key, value, isStrictComparable(value)]; + } + return result; + } + + /** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ + function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; + } + + /** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ + function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; + } + + /** + * Creates an array of the own enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbols = !nativeGetSymbols ? stubArray : function(object) { + if (object == null) { + return []; + } + object = Object(object); + return arrayFilter(nativeGetSymbols(object), function(symbol) { + return propertyIsEnumerable.call(object, symbol); + }); + }; + + /** + * Creates an array of the own and inherited enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { + var result = []; + while (object) { + arrayPush(result, getSymbols(object)); + object = getPrototype(object); + } + return result; + }; + + /** + * Gets the `toStringTag` of `value`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + var getTag = baseGetTag; + + // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. + if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || + (Map && getTag(new Map) != mapTag) || + (Promise && getTag(Promise.resolve()) != promiseTag) || + (Set && getTag(new Set) != setTag) || + (WeakMap && getTag(new WeakMap) != weakMapTag)) { + getTag = function(value) { + var result = baseGetTag(value), + Ctor = result == objectTag ? value.constructor : undefined, + ctorString = Ctor ? toSource(Ctor) : ''; + + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: return dataViewTag; + case mapCtorString: return mapTag; + case promiseCtorString: return promiseTag; + case setCtorString: return setTag; + case weakMapCtorString: return weakMapTag; + } + } + return result; + }; + } + + /** + * Gets the view, applying any `transforms` to the `start` and `end` positions. + * + * @private + * @param {number} start The start of the view. + * @param {number} end The end of the view. + * @param {Array} transforms The transformations to apply to the view. + * @returns {Object} Returns an object containing the `start` and `end` + * positions of the view. + */ + function getView(start, end, transforms) { + var index = -1, + length = transforms.length; + + while (++index < length) { + var data = transforms[index], + size = data.size; + + switch (data.type) { + case 'drop': start += size; break; + case 'dropRight': end -= size; break; + case 'take': end = nativeMin(end, start + size); break; + case 'takeRight': start = nativeMax(start, end - size); break; + } + } + return { 'start': start, 'end': end }; + } + + /** + * Extracts wrapper details from the `source` body comment. + * + * @private + * @param {string} source The source to inspect. + * @returns {Array} Returns the wrapper details. + */ + function getWrapDetails(source) { + var match = source.match(reWrapDetails); + return match ? match[1].split(reSplitDetails) : []; + } + + /** + * Checks if `path` exists on `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @param {Function} hasFunc The function to check properties. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + */ + function hasPath(object, path, hasFunc) { + path = castPath(path, object); + + var index = -1, + length = path.length, + result = false; + + while (++index < length) { + var key = toKey(path[index]); + if (!(result = object != null && hasFunc(object, key))) { + break; + } + object = object[key]; + } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return !!length && isLength(length) && isIndex(key, length) && + (isArray(object) || isArguments(object)); + } + + /** + * Initializes an array clone. + * + * @private + * @param {Array} array The array to clone. + * @returns {Array} Returns the initialized clone. + */ + function initCloneArray(array) { + var length = array.length, + result = new array.constructor(length); + + // Add properties assigned by `RegExp#exec`. + if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { + result.index = array.index; + result.input = array.input; + } + return result; + } + + /** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneObject(object) { + return (typeof object.constructor == 'function' && !isPrototype(object)) + ? baseCreate(getPrototype(object)) + : {}; + } + + /** + * Initializes an object clone based on its `toStringTag`. + * + * **Note:** This function only supports cloning values with tags of + * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`. + * + * @private + * @param {Object} object The object to clone. + * @param {string} tag The `toStringTag` of the object to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneByTag(object, tag, isDeep) { + var Ctor = object.constructor; + switch (tag) { + case arrayBufferTag: + return cloneArrayBuffer(object); + + case boolTag: + case dateTag: + return new Ctor(+object); + + case dataViewTag: + return cloneDataView(object, isDeep); + + case float32Tag: case float64Tag: + case int8Tag: case int16Tag: case int32Tag: + case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: + return cloneTypedArray(object, isDeep); + + case mapTag: + return new Ctor; + + case numberTag: + case stringTag: + return new Ctor(object); + + case regexpTag: + return cloneRegExp(object); + + case setTag: + return new Ctor; + + case symbolTag: + return cloneSymbol(object); + } + } + + /** + * Inserts wrapper `details` in a comment at the top of the `source` body. + * + * @private + * @param {string} source The source to modify. + * @returns {Array} details The details to insert. + * @returns {string} Returns the modified source. + */ + function insertWrapDetails(source, details) { + var length = details.length; + if (!length) { + return source; + } + var lastIndex = length - 1; + details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; + details = details.join(length > 2 ? ', ' : ' '); + return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); + } + + /** + * Checks if `value` is a flattenable `arguments` object or array. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. + */ + function isFlattenable(value) { + return isArray(value) || isArguments(value) || + !!(spreadableSymbol && value && value[spreadableSymbol]); + } + + /** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ + function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); + } + + /** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ + function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; + } + + /** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ + function isKey(value, object) { + if (isArray(value)) { + return false; + } + var type = typeof value; + if (type == 'number' || type == 'symbol' || type == 'boolean' || + value == null || isSymbol(value)) { + return true; + } + return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || + (object != null && value in Object(object)); + } + + /** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ + function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); + } + + /** + * Checks if `func` has a lazy counterpart. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` has a lazy counterpart, + * else `false`. + */ + function isLaziable(func) { + var funcName = getFuncName(func), + other = lodash[funcName]; + + if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { + return false; + } + if (func === other) { + return true; + } + var data = getData(other); + return !!data && func === data[0]; + } + + /** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ + function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); + } + + /** + * Checks if `func` is capable of being masked. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `func` is maskable, else `false`. + */ + var isMaskable = coreJsData ? isFunction : stubFalse; + + /** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ + function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; + + return value === proto; + } + + /** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ + function isStrictComparable(value) { + return value === value && !isObject(value); + } + + /** + * A specialized version of `matchesProperty` for source values suitable + * for strict equality comparisons, i.e. `===`. + * + * @private + * @param {string} key The key of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function matchesStrictComparable(key, srcValue) { + return function(object) { + if (object == null) { + return false; + } + return object[key] === srcValue && + (srcValue !== undefined || (key in Object(object))); + }; + } + + /** + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * + * @private + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. + */ + function memoizeCapped(func) { + var result = memoize(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); + } + return key; + }); + + var cache = result.cache; + return result; + } + + /** + * Merges the function metadata of `source` into `data`. + * + * Merging metadata reduces the number of wrappers used to invoke a function. + * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` + * may be applied regardless of execution order. Methods like `_.ary` and + * `_.rearg` modify function arguments, making the order in which they are + * executed important, preventing the merging of metadata. However, we make + * an exception for a safe combined case where curried functions have `_.ary` + * and or `_.rearg` applied. + * + * @private + * @param {Array} data The destination metadata. + * @param {Array} source The source metadata. + * @returns {Array} Returns `data`. + */ + function mergeData(data, source) { + var bitmask = data[1], + srcBitmask = source[1], + newBitmask = bitmask | srcBitmask, + isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG); + + var isCombo = + ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) || + ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) || + ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG)); + + // Exit early if metadata can't be merged. + if (!(isCommon || isCombo)) { + return data; + } + // Use source `thisArg` if available. + if (srcBitmask & WRAP_BIND_FLAG) { + data[2] = source[2]; + // Set when currying a bound function. + newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG; + } + // Compose partial arguments. + var value = source[3]; + if (value) { + var partials = data[3]; + data[3] = partials ? composeArgs(partials, value, source[4]) : value; + data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; + } + // Compose partial right arguments. + value = source[5]; + if (value) { + partials = data[5]; + data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; + data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; + } + // Use source `argPos` if available. + value = source[7]; + if (value) { + data[7] = value; + } + // Use source `ary` if it's smaller. + if (srcBitmask & WRAP_ARY_FLAG) { + data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); + } + // Use source `arity` if one is not provided. + if (data[9] == null) { + data[9] = source[9]; + } + // Use source `func` and merge bitmasks. + data[0] = source[0]; + data[1] = newBitmask; + + return data; + } + + /** + * This function is like + * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * except that it includes inherited enumerable properties. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function nativeKeysIn(object) { + var result = []; + if (object != null) { + for (var key in Object(object)) { + result.push(key); + } + } + return result; + } + + /** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ + function objectToString(value) { + return nativeObjectToString.call(value); + } + + /** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ + function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; + } + + /** + * Gets the parent value at `path` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} path The path to get the parent value of. + * @returns {*} Returns the parent value. + */ + function parent(object, path) { + return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1)); + } + + /** + * Reorder `array` according to the specified indexes where the element at + * the first index is assigned as the first element, the element at + * the second index is assigned as the second element, and so on. + * + * @private + * @param {Array} array The array to reorder. + * @param {Array} indexes The arranged array indexes. + * @returns {Array} Returns `array`. + */ + function reorder(array, indexes) { + var arrLength = array.length, + length = nativeMin(indexes.length, arrLength), + oldArray = copyArray(array); + + while (length--) { + var index = indexes[length]; + array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; + } + return array; + } + + /** + * Sets metadata for `func`. + * + * **Note:** If this function becomes hot, i.e. is invoked a lot in a short + * period of time, it will trip its breaker and transition to an identity + * function to avoid garbage collection pauses in V8. See + * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) + * for more details. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var setData = shortOut(baseSetData); + + /** + * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout). + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @returns {number|Object} Returns the timer id or timeout object. + */ + var setTimeout = ctxSetTimeout || function(func, wait) { + return root.setTimeout(func, wait); + }; + + /** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var setToString = shortOut(baseSetToString); + + /** + * Sets the `toString` method of `wrapper` to mimic the source of `reference` + * with wrapper details in a comment at the top of the source body. + * + * @private + * @param {Function} wrapper The function to modify. + * @param {Function} reference The reference function. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @returns {Function} Returns `wrapper`. + */ + function setWrapToString(wrapper, reference, bitmask) { + var source = (reference + ''); + return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))); + } + + /** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ + function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; + } + + /** + * A specialized version of `_.shuffle` which mutates and sets the size of `array`. + * + * @private + * @param {Array} array The array to shuffle. + * @param {number} [size=array.length] The size of `array`. + * @returns {Array} Returns `array`. + */ + function shuffleSelf(array, size) { + var index = -1, + length = array.length, + lastIndex = length - 1; + + size = size === undefined ? length : size; + while (++index < size) { + var rand = baseRandom(index, lastIndex), + value = array[rand]; + + array[rand] = array[index]; + array[index] = value; + } + array.length = size; + return array; + } + + /** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. + */ + var stringToPath = memoizeCapped(function(string) { + var result = []; + if (string.charCodeAt(0) === 46 /* . */) { + result.push(''); + } + string.replace(rePropName, function(match, number, quote, subString) { + result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; + }); + + /** + * Converts `value` to a string key if it's not a string or symbol. + * + * @private + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. + */ + function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ + function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; + } + + /** + * Updates wrapper `details` based on `bitmask` flags. + * + * @private + * @returns {Array} details The details to modify. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @returns {Array} Returns `details`. + */ + function updateWrapDetails(details, bitmask) { + arrayEach(wrapFlags, function(pair) { + var value = '_.' + pair[0]; + if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { + details.push(value); + } + }); + return details.sort(); + } + + /** + * Creates a clone of `wrapper`. + * + * @private + * @param {Object} wrapper The wrapper to clone. + * @returns {Object} Returns the cloned wrapper. + */ + function wrapperClone(wrapper) { + if (wrapper instanceof LazyWrapper) { + return wrapper.clone(); + } + var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); + result.__actions__ = copyArray(wrapper.__actions__); + result.__index__ = wrapper.__index__; + result.__values__ = wrapper.__values__; + return result; + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of elements split into groups the length of `size`. + * If `array` can't be split evenly, the final chunk will be the remaining + * elements. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to process. + * @param {number} [size=1] The length of each chunk + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the new array of chunks. + * @example + * + * _.chunk(['a', 'b', 'c', 'd'], 2); + * // => [['a', 'b'], ['c', 'd']] + * + * _.chunk(['a', 'b', 'c', 'd'], 3); + * // => [['a', 'b', 'c'], ['d']] + */ + function chunk(array, size, guard) { + if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { + size = 1; + } else { + size = nativeMax(toInteger(size), 0); + } + var length = array == null ? 0 : array.length; + if (!length || size < 1) { + return []; + } + var index = 0, + resIndex = 0, + result = Array(nativeCeil(length / size)); + + while (index < length) { + result[resIndex++] = baseSlice(array, index, (index += size)); + } + return result; + } + + /** + * Creates an array with all falsey values removed. The values `false`, `null`, + * `0`, `""`, `undefined`, and `NaN` are falsey. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to compact. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.compact([0, 1, false, 2, '', 3]); + * // => [1, 2, 3] + */ + function compact(array) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * Creates a new array concatenating `array` with any additional arrays + * and/or values. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to concatenate. + * @param {...*} [values] The values to concatenate. + * @returns {Array} Returns the new concatenated array. + * @example + * + * var array = [1]; + * var other = _.concat(array, 2, [3], [[4]]); + * + * console.log(other); + * // => [1, 2, 3, [4]] + * + * console.log(array); + * // => [1] + */ + function concat() { + var length = arguments.length; + if (!length) { + return []; + } + var args = Array(length - 1), + array = arguments[0], + index = length; + + while (index--) { + args[index - 1] = arguments[index]; + } + return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); + } + + /** + * Creates an array of `array` values not included in the other given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. + * + * **Note:** Unlike `_.pullAll`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @see _.without, _.xor + * @example + * + * _.difference([2, 1], [2, 3]); + * // => [1] + */ + var difference = baseRest(function(array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) + : []; + }); + + /** + * This method is like `_.difference` except that it accepts `iteratee` which + * is invoked for each element of `array` and `values` to generate the criterion + * by which they're compared. The order and references of result values are + * determined by the first array. The iteratee is invoked with one argument: + * (value). + * + * **Note:** Unlike `_.pullAllBy`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [1.2] + * + * // The `_.property` iteratee shorthand. + * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); + * // => [{ 'x': 2 }] + */ + var differenceBy = baseRest(function(array, values) { + var iteratee = last(values); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)) + : []; + }); + + /** + * This method is like `_.difference` except that it accepts `comparator` + * which is invoked to compare elements of `array` to `values`. The order and + * references of result values are determined by the first array. The comparator + * is invoked with two arguments: (arrVal, othVal). + * + * **Note:** Unlike `_.pullAllWith`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * + * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); + * // => [{ 'x': 2, 'y': 1 }] + */ + var differenceWith = baseRest(function(array, values) { + var comparator = last(values); + if (isArrayLikeObject(comparator)) { + comparator = undefined; + } + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) + : []; + }); + + /** + * Creates a slice of `array` with `n` elements dropped from the beginning. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.drop([1, 2, 3]); + * // => [2, 3] + * + * _.drop([1, 2, 3], 2); + * // => [3] + * + * _.drop([1, 2, 3], 5); + * // => [] + * + * _.drop([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function drop(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + return baseSlice(array, n < 0 ? 0 : n, length); + } + + /** + * Creates a slice of `array` with `n` elements dropped from the end. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropRight([1, 2, 3]); + * // => [1, 2] + * + * _.dropRight([1, 2, 3], 2); + * // => [1] + * + * _.dropRight([1, 2, 3], 5); + * // => [] + * + * _.dropRight([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function dropRight(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + n = length - n; + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` excluding elements dropped from the end. + * Elements are dropped until `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.dropRightWhile(users, function(o) { return !o.active; }); + * // => objects for ['barney'] + * + * // The `_.matches` iteratee shorthand. + * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false }); + * // => objects for ['barney', 'fred'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.dropRightWhile(users, ['active', false]); + * // => objects for ['barney'] + * + * // The `_.property` iteratee shorthand. + * _.dropRightWhile(users, 'active'); + * // => objects for ['barney', 'fred', 'pebbles'] + */ + function dropRightWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), true, true) + : []; + } + + /** + * Creates a slice of `array` excluding elements dropped from the beginning. + * Elements are dropped until `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.dropWhile(users, function(o) { return !o.active; }); + * // => objects for ['pebbles'] + * + * // The `_.matches` iteratee shorthand. + * _.dropWhile(users, { 'user': 'barney', 'active': false }); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.dropWhile(users, ['active', false]); + * // => objects for ['pebbles'] + * + * // The `_.property` iteratee shorthand. + * _.dropWhile(users, 'active'); + * // => objects for ['barney', 'fred', 'pebbles'] + */ + function dropWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), true) + : []; + } + + /** + * Fills elements of `array` with `value` from `start` up to, but not + * including, `end`. + * + * **Note:** This method mutates `array`. + * + * @static + * @memberOf _ + * @since 3.2.0 + * @category Array + * @param {Array} array The array to fill. + * @param {*} value The value to fill `array` with. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.fill(array, 'a'); + * console.log(array); + * // => ['a', 'a', 'a'] + * + * _.fill(Array(3), 2); + * // => [2, 2, 2] + * + * _.fill([4, 6, 8, 10], '*', 1, 3); + * // => [4, '*', '*', 10] + */ + function fill(array, value, start, end) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { + start = 0; + end = length; + } + return baseFill(array, value, start, end); + } + + /** + * This method is like `_.find` except that it returns the index of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.findIndex(users, function(o) { return o.user == 'barney'; }); + * // => 0 + * + * // The `_.matches` iteratee shorthand. + * _.findIndex(users, { 'user': 'fred', 'active': false }); + * // => 1 + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findIndex(users, ['active', false]); + * // => 0 + * + * // The `_.property` iteratee shorthand. + * _.findIndex(users, 'active'); + * // => 2 + */ + function findIndex(array, predicate, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseFindIndex(array, getIteratee(predicate, 3), index); + } + + /** + * This method is like `_.findIndex` except that it iterates over elements + * of `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=array.length-1] The index to search from. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); + * // => 2 + * + * // The `_.matches` iteratee shorthand. + * _.findLastIndex(users, { 'user': 'barney', 'active': true }); + * // => 0 + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findLastIndex(users, ['active', false]); + * // => 2 + * + * // The `_.property` iteratee shorthand. + * _.findLastIndex(users, 'active'); + * // => 0 + */ + function findLastIndex(array, predicate, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = length - 1; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = fromIndex < 0 + ? nativeMax(length + index, 0) + : nativeMin(index, length - 1); + } + return baseFindIndex(array, getIteratee(predicate, 3), index, true); + } + + /** + * Flattens `array` a single level deep. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flatten([1, [2, [3, [4]], 5]]); + * // => [1, 2, [3, [4]], 5] + */ + function flatten(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, 1) : []; + } + + /** + * Recursively flattens `array`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flattenDeep([1, [2, [3, [4]], 5]]); + * // => [1, 2, 3, 4, 5] + */ + function flattenDeep(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, INFINITY) : []; + } + + /** + * Recursively flatten `array` up to `depth` times. + * + * @static + * @memberOf _ + * @since 4.4.0 + * @category Array + * @param {Array} array The array to flatten. + * @param {number} [depth=1] The maximum recursion depth. + * @returns {Array} Returns the new flattened array. + * @example + * + * var array = [1, [2, [3, [4]], 5]]; + * + * _.flattenDepth(array, 1); + * // => [1, 2, [3, [4]], 5] + * + * _.flattenDepth(array, 2); + * // => [1, 2, 3, [4], 5] + */ + function flattenDepth(array, depth) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + depth = depth === undefined ? 1 : toInteger(depth); + return baseFlatten(array, depth); + } + + /** + * The inverse of `_.toPairs`; this method returns an object composed + * from key-value `pairs`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} pairs The key-value pairs. + * @returns {Object} Returns the new object. + * @example + * + * _.fromPairs([['a', 1], ['b', 2]]); + * // => { 'a': 1, 'b': 2 } + */ + function fromPairs(pairs) { + var index = -1, + length = pairs == null ? 0 : pairs.length, + result = {}; + + while (++index < length) { + var pair = pairs[index]; + result[pair[0]] = pair[1]; + } + return result; + } + + /** + * Gets the first element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @alias first + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the first element of `array`. + * @example + * + * _.head([1, 2, 3]); + * // => 1 + * + * _.head([]); + * // => undefined + */ + function head(array) { + return (array && array.length) ? array[0] : undefined; + } + + /** + * Gets the index at which the first occurrence of `value` is found in `array` + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it's used as the + * offset from the end of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.indexOf([1, 2, 1, 2], 2); + * // => 1 + * + * // Search from the `fromIndex`. + * _.indexOf([1, 2, 1, 2], 2, 2); + * // => 3 + */ + function indexOf(array, value, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseIndexOf(array, value, index); + } + + /** + * Gets all but the last element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.initial([1, 2, 3]); + * // => [1, 2] + */ + function initial(array) { + var length = array == null ? 0 : array.length; + return length ? baseSlice(array, 0, -1) : []; + } + + /** + * Creates an array of unique values that are included in all given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * _.intersection([2, 1], [2, 3]); + * // => [2] + */ + var intersection = baseRest(function(arrays) { + var mapped = arrayMap(arrays, castArrayLikeObject); + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped) + : []; + }); + + /** + * This method is like `_.intersection` except that it accepts `iteratee` + * which is invoked for each element of each `arrays` to generate the criterion + * by which they're compared. The order and references of result values are + * determined by the first array. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [2.1] + * + * // The `_.property` iteratee shorthand. + * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }] + */ + var intersectionBy = baseRest(function(arrays) { + var iteratee = last(arrays), + mapped = arrayMap(arrays, castArrayLikeObject); + + if (iteratee === last(mapped)) { + iteratee = undefined; + } else { + mapped.pop(); + } + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped, getIteratee(iteratee, 2)) + : []; + }); + + /** + * This method is like `_.intersection` except that it accepts `comparator` + * which is invoked to compare elements of `arrays`. The order and references + * of result values are determined by the first array. The comparator is + * invoked with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.intersectionWith(objects, others, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }] + */ + var intersectionWith = baseRest(function(arrays) { + var comparator = last(arrays), + mapped = arrayMap(arrays, castArrayLikeObject); + + comparator = typeof comparator == 'function' ? comparator : undefined; + if (comparator) { + mapped.pop(); + } + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped, undefined, comparator) + : []; + }); + + /** + * Converts all elements in `array` into a string separated by `separator`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to convert. + * @param {string} [separator=','] The element separator. + * @returns {string} Returns the joined string. + * @example + * + * _.join(['a', 'b', 'c'], '~'); + * // => 'a~b~c' + */ + function join(array, separator) { + return array == null ? '' : nativeJoin.call(array, separator); + } + + /** + * Gets the last element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the last element of `array`. + * @example + * + * _.last([1, 2, 3]); + * // => 3 + */ + function last(array) { + var length = array == null ? 0 : array.length; + return length ? array[length - 1] : undefined; + } + + /** + * This method is like `_.indexOf` except that it iterates over elements of + * `array` from right to left. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=array.length-1] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.lastIndexOf([1, 2, 1, 2], 2); + * // => 3 + * + * // Search from the `fromIndex`. + * _.lastIndexOf([1, 2, 1, 2], 2, 2); + * // => 1 + */ + function lastIndexOf(array, value, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = length; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1); + } + return value === value + ? strictLastIndexOf(array, value, index) + : baseFindIndex(array, baseIsNaN, index, true); + } + + /** + * Gets the element at index `n` of `array`. If `n` is negative, the nth + * element from the end is returned. + * + * @static + * @memberOf _ + * @since 4.11.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=0] The index of the element to return. + * @returns {*} Returns the nth element of `array`. + * @example + * + * var array = ['a', 'b', 'c', 'd']; + * + * _.nth(array, 1); + * // => 'b' + * + * _.nth(array, -2); + * // => 'c'; + */ + function nth(array, n) { + return (array && array.length) ? baseNth(array, toInteger(n)) : undefined; + } + + /** + * Removes all given values from `array` using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove` + * to remove elements from an array by predicate. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {...*} [values] The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = ['a', 'b', 'c', 'a', 'b', 'c']; + * + * _.pull(array, 'a', 'c'); + * console.log(array); + * // => ['b', 'b'] + */ + var pull = baseRest(pullAll); + + /** + * This method is like `_.pull` except that it accepts an array of values to remove. + * + * **Note:** Unlike `_.difference`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = ['a', 'b', 'c', 'a', 'b', 'c']; + * + * _.pullAll(array, ['a', 'c']); + * console.log(array); + * // => ['b', 'b'] + */ + function pullAll(array, values) { + return (array && array.length && values && values.length) + ? basePullAll(array, values) + : array; + } + + /** + * This method is like `_.pullAll` except that it accepts `iteratee` which is + * invoked for each element of `array` and `values` to generate the criterion + * by which they're compared. The iteratee is invoked with one argument: (value). + * + * **Note:** Unlike `_.differenceBy`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns `array`. + * @example + * + * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; + * + * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x'); + * console.log(array); + * // => [{ 'x': 2 }] + */ + function pullAllBy(array, values, iteratee) { + return (array && array.length && values && values.length) + ? basePullAll(array, values, getIteratee(iteratee, 2)) + : array; + } + + /** + * This method is like `_.pullAll` except that it accepts `comparator` which + * is invoked to compare elements of `array` to `values`. The comparator is + * invoked with two arguments: (arrVal, othVal). + * + * **Note:** Unlike `_.differenceWith`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns `array`. + * @example + * + * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }]; + * + * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual); + * console.log(array); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }] + */ + function pullAllWith(array, values, comparator) { + return (array && array.length && values && values.length) + ? basePullAll(array, values, undefined, comparator) + : array; + } + + /** + * Removes elements from `array` corresponding to `indexes` and returns an + * array of removed elements. + * + * **Note:** Unlike `_.at`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {...(number|number[])} [indexes] The indexes of elements to remove. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = ['a', 'b', 'c', 'd']; + * var pulled = _.pullAt(array, [1, 3]); + * + * console.log(array); + * // => ['a', 'c'] + * + * console.log(pulled); + * // => ['b', 'd'] + */ + var pullAt = flatRest(function(array, indexes) { + var length = array == null ? 0 : array.length, + result = baseAt(array, indexes); + + basePullAt(array, arrayMap(indexes, function(index) { + return isIndex(index, length) ? +index : index; + }).sort(compareAscending)); + + return result; + }); + + /** + * Removes all elements from `array` that `predicate` returns truthy for + * and returns an array of the removed elements. The predicate is invoked + * with three arguments: (value, index, array). + * + * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull` + * to pull elements from an array by value. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = [1, 2, 3, 4]; + * var evens = _.remove(array, function(n) { + * return n % 2 == 0; + * }); + * + * console.log(array); + * // => [1, 3] + * + * console.log(evens); + * // => [2, 4] + */ + function remove(array, predicate) { + var result = []; + if (!(array && array.length)) { + return result; + } + var index = -1, + indexes = [], + length = array.length; + + predicate = getIteratee(predicate, 3); + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result.push(value); + indexes.push(index); + } + } + basePullAt(array, indexes); + return result; + } + + /** + * Reverses `array` so that the first element becomes the last, the second + * element becomes the second to last, and so on. + * + * **Note:** This method mutates `array` and is based on + * [`Array#reverse`](https://mdn.io/Array/reverse). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.reverse(array); + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function reverse(array) { + return array == null ? array : nativeReverse.call(array); + } + + /** + * Creates a slice of `array` from `start` up to, but not including, `end`. + * + * **Note:** This method is used instead of + * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are + * returned. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function slice(array, start, end) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { + start = 0; + end = length; + } + else { + start = start == null ? 0 : toInteger(start); + end = end === undefined ? length : toInteger(end); + } + return baseSlice(array, start, end); + } + + /** + * Uses a binary search to determine the lowest index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedIndex([30, 50], 40); + * // => 1 + */ + function sortedIndex(array, value) { + return baseSortedIndex(array, value); + } + + /** + * This method is like `_.sortedIndex` except that it accepts `iteratee` + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * var objects = [{ 'x': 4 }, { 'x': 5 }]; + * + * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); + * // => 0 + * + * // The `_.property` iteratee shorthand. + * _.sortedIndexBy(objects, { 'x': 4 }, 'x'); + * // => 0 + */ + function sortedIndexBy(array, value, iteratee) { + return baseSortedIndexBy(array, value, getIteratee(iteratee, 2)); + } + + /** + * This method is like `_.indexOf` except that it performs a binary + * search on a sorted `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.sortedIndexOf([4, 5, 5, 5, 6], 5); + * // => 1 + */ + function sortedIndexOf(array, value) { + var length = array == null ? 0 : array.length; + if (length) { + var index = baseSortedIndex(array, value); + if (index < length && eq(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * This method is like `_.sortedIndex` except that it returns the highest + * index at which `value` should be inserted into `array` in order to + * maintain its sort order. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedLastIndex([4, 5, 5, 5, 6], 5); + * // => 4 + */ + function sortedLastIndex(array, value) { + return baseSortedIndex(array, value, true); + } + + /** + * This method is like `_.sortedLastIndex` except that it accepts `iteratee` + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * var objects = [{ 'x': 4 }, { 'x': 5 }]; + * + * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); + * // => 1 + * + * // The `_.property` iteratee shorthand. + * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x'); + * // => 1 + */ + function sortedLastIndexBy(array, value, iteratee) { + return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true); + } + + /** + * This method is like `_.lastIndexOf` except that it performs a binary + * search on a sorted `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); + * // => 3 + */ + function sortedLastIndexOf(array, value) { + var length = array == null ? 0 : array.length; + if (length) { + var index = baseSortedIndex(array, value, true) - 1; + if (eq(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * This method is like `_.uniq` except that it's designed and optimized + * for sorted arrays. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.sortedUniq([1, 1, 2]); + * // => [1, 2] + */ + function sortedUniq(array) { + return (array && array.length) + ? baseSortedUniq(array) + : []; + } + + /** + * This method is like `_.uniqBy` except that it's designed and optimized + * for sorted arrays. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); + * // => [1.1, 2.3] + */ + function sortedUniqBy(array, iteratee) { + return (array && array.length) + ? baseSortedUniq(array, getIteratee(iteratee, 2)) + : []; + } + + /** + * Gets all but the first element of `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.tail([1, 2, 3]); + * // => [2, 3] + */ + function tail(array) { + var length = array == null ? 0 : array.length; + return length ? baseSlice(array, 1, length) : []; + } + + /** + * Creates a slice of `array` with `n` elements taken from the beginning. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.take([1, 2, 3]); + * // => [1] + * + * _.take([1, 2, 3], 2); + * // => [1, 2] + * + * _.take([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.take([1, 2, 3], 0); + * // => [] + */ + function take(array, n, guard) { + if (!(array && array.length)) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` with `n` elements taken from the end. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeRight([1, 2, 3]); + * // => [3] + * + * _.takeRight([1, 2, 3], 2); + * // => [2, 3] + * + * _.takeRight([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.takeRight([1, 2, 3], 0); + * // => [] + */ + function takeRight(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + n = length - n; + return baseSlice(array, n < 0 ? 0 : n, length); + } + + /** + * Creates a slice of `array` with elements taken from the end. Elements are + * taken until `predicate` returns falsey. The predicate is invoked with + * three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.takeRightWhile(users, function(o) { return !o.active; }); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.matches` iteratee shorthand. + * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false }); + * // => objects for ['pebbles'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.takeRightWhile(users, ['active', false]); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.property` iteratee shorthand. + * _.takeRightWhile(users, 'active'); + * // => [] + */ + function takeRightWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), false, true) + : []; + } + + /** + * Creates a slice of `array` with elements taken from the beginning. Elements + * are taken until `predicate` returns falsey. The predicate is invoked with + * three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.takeWhile(users, function(o) { return !o.active; }); + * // => objects for ['barney', 'fred'] + * + * // The `_.matches` iteratee shorthand. + * _.takeWhile(users, { 'user': 'barney', 'active': false }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.takeWhile(users, ['active', false]); + * // => objects for ['barney', 'fred'] + * + * // The `_.property` iteratee shorthand. + * _.takeWhile(users, 'active'); + * // => [] + */ + function takeWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3)) + : []; + } + + /** + * Creates an array of unique values, in order, from all given arrays using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.union([2], [1, 2]); + * // => [2, 1] + */ + var union = baseRest(function(arrays) { + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); + }); + + /** + * This method is like `_.union` except that it accepts `iteratee` which is + * invoked for each element of each `arrays` to generate the criterion by + * which uniqueness is computed. Result values are chosen from the first + * array in which the value occurs. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.unionBy([2.1], [1.2, 2.3], Math.floor); + * // => [2.1, 1.2] + * + * // The `_.property` iteratee shorthand. + * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + var unionBy = baseRest(function(arrays) { + var iteratee = last(arrays); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)); + }); + + /** + * This method is like `_.union` except that it accepts `comparator` which + * is invoked to compare elements of `arrays`. Result values are chosen from + * the first array in which the value occurs. The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of combined values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.unionWith(objects, others, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] + */ + var unionWith = baseRest(function(arrays) { + var comparator = last(arrays); + comparator = typeof comparator == 'function' ? comparator : undefined; + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); + }); + + /** + * Creates a duplicate-free version of an array, using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons, in which only the first occurrence of each element + * is kept. The order of result values is determined by the order they occur + * in the array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniq([2, 1, 2]); + * // => [2, 1] + */ + function uniq(array) { + return (array && array.length) ? baseUniq(array) : []; + } + + /** + * This method is like `_.uniq` except that it accepts `iteratee` which is + * invoked for each element in `array` to generate the criterion by which + * uniqueness is computed. The order of result values is determined by the + * order they occur in the array. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniqBy([2.1, 1.2, 2.3], Math.floor); + * // => [2.1, 1.2] + * + * // The `_.property` iteratee shorthand. + * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + function uniqBy(array, iteratee) { + return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : []; + } + + /** + * This method is like `_.uniq` except that it accepts `comparator` which + * is invoked to compare elements of `array`. The order of result values is + * determined by the order they occur in the array.The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.uniqWith(objects, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }] + */ + function uniqWith(array, comparator) { + comparator = typeof comparator == 'function' ? comparator : undefined; + return (array && array.length) ? baseUniq(array, undefined, comparator) : []; + } + + /** + * This method is like `_.zip` except that it accepts an array of grouped + * elements and creates an array regrouping the elements to their pre-zip + * configuration. + * + * @static + * @memberOf _ + * @since 1.2.0 + * @category Array + * @param {Array} array The array of grouped elements to process. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); + * // => [['a', 1, true], ['b', 2, false]] + * + * _.unzip(zipped); + * // => [['a', 'b'], [1, 2], [true, false]] + */ + function unzip(array) { + if (!(array && array.length)) { + return []; + } + var length = 0; + array = arrayFilter(array, function(group) { + if (isArrayLikeObject(group)) { + length = nativeMax(group.length, length); + return true; + } + }); + return baseTimes(length, function(index) { + return arrayMap(array, baseProperty(index)); + }); + } + + /** + * This method is like `_.unzip` except that it accepts `iteratee` to specify + * how regrouped values should be combined. The iteratee is invoked with the + * elements of each group: (...group). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Array + * @param {Array} array The array of grouped elements to process. + * @param {Function} [iteratee=_.identity] The function to combine + * regrouped values. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip([1, 2], [10, 20], [100, 200]); + * // => [[1, 10, 100], [2, 20, 200]] + * + * _.unzipWith(zipped, _.add); + * // => [3, 30, 300] + */ + function unzipWith(array, iteratee) { + if (!(array && array.length)) { + return []; + } + var result = unzip(array); + if (iteratee == null) { + return result; + } + return arrayMap(result, function(group) { + return apply(iteratee, undefined, group); + }); + } + + /** + * Creates an array excluding all given values using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * **Note:** Unlike `_.pull`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...*} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @see _.difference, _.xor + * @example + * + * _.without([2, 1, 2, 3], 1, 2); + * // => [3] + */ + var without = baseRest(function(array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, values) + : []; + }); + + /** + * Creates an array of unique values that is the + * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) + * of the given arrays. The order of result values is determined by the order + * they occur in the arrays. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of filtered values. + * @see _.difference, _.without + * @example + * + * _.xor([2, 1], [2, 3]); + * // => [1, 3] + */ + var xor = baseRest(function(arrays) { + return baseXor(arrayFilter(arrays, isArrayLikeObject)); + }); + + /** + * This method is like `_.xor` except that it accepts `iteratee` which is + * invoked for each element of each `arrays` to generate the criterion by + * which by which they're compared. The order of result values is determined + * by the order they occur in the arrays. The iteratee is invoked with one + * argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [1.2, 3.4] + * + * // The `_.property` iteratee shorthand. + * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 2 }] + */ + var xorBy = baseRest(function(arrays) { + var iteratee = last(arrays); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2)); + }); + + /** + * This method is like `_.xor` except that it accepts `comparator` which is + * invoked to compare elements of `arrays`. The order of result values is + * determined by the order they occur in the arrays. The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.xorWith(objects, others, _.isEqual); + * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] + */ + var xorWith = baseRest(function(arrays) { + var comparator = last(arrays); + comparator = typeof comparator == 'function' ? comparator : undefined; + return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator); + }); + + /** + * Creates an array of grouped elements, the first of which contains the + * first elements of the given arrays, the second of which contains the + * second elements of the given arrays, and so on. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zip(['a', 'b'], [1, 2], [true, false]); + * // => [['a', 1, true], ['b', 2, false]] + */ + var zip = baseRest(unzip); + + /** + * This method is like `_.fromPairs` except that it accepts two arrays, + * one of property identifiers and one of corresponding values. + * + * @static + * @memberOf _ + * @since 0.4.0 + * @category Array + * @param {Array} [props=[]] The property identifiers. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObject(['a', 'b'], [1, 2]); + * // => { 'a': 1, 'b': 2 } + */ + function zipObject(props, values) { + return baseZipObject(props || [], values || [], assignValue); + } + + /** + * This method is like `_.zipObject` except that it supports property paths. + * + * @static + * @memberOf _ + * @since 4.1.0 + * @category Array + * @param {Array} [props=[]] The property identifiers. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); + * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } + */ + function zipObjectDeep(props, values) { + return baseZipObject(props || [], values || [], baseSet); + } + + /** + * This method is like `_.zip` except that it accepts `iteratee` to specify + * how grouped values should be combined. The iteratee is invoked with the + * elements of each group: (...group). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @param {Function} [iteratee=_.identity] The function to combine + * grouped values. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { + * return a + b + c; + * }); + * // => [111, 222] + */ + var zipWith = baseRest(function(arrays) { + var length = arrays.length, + iteratee = length > 1 ? arrays[length - 1] : undefined; + + iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined; + return unzipWith(arrays, iteratee); + }); + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` wrapper instance that wraps `value` with explicit method + * chain sequences enabled. The result of such sequences must be unwrapped + * with `_#value`. + * + * @static + * @memberOf _ + * @since 1.3.0 + * @category Seq + * @param {*} value The value to wrap. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'pebbles', 'age': 1 } + * ]; + * + * var youngest = _ + * .chain(users) + * .sortBy('age') + * .map(function(o) { + * return o.user + ' is ' + o.age; + * }) + * .head() + * .value(); + * // => 'pebbles is 1' + */ + function chain(value) { + var result = lodash(value); + result.__chain__ = true; + return result; + } + + /** + * This method invokes `interceptor` and returns `value`. The interceptor + * is invoked with one argument; (value). The purpose of this method is to + * "tap into" a method chain sequence in order to modify intermediate results. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @returns {*} Returns `value`. + * @example + * + * _([1, 2, 3]) + * .tap(function(array) { + * // Mutate input array. + * array.pop(); + * }) + * .reverse() + * .value(); + * // => [2, 1] + */ + function tap(value, interceptor) { + interceptor(value); + return value; + } + + /** + * This method is like `_.tap` except that it returns the result of `interceptor`. + * The purpose of this method is to "pass thru" values replacing intermediate + * results in a method chain sequence. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Seq + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @returns {*} Returns the result of `interceptor`. + * @example + * + * _(' abc ') + * .chain() + * .trim() + * .thru(function(value) { + * return [value]; + * }) + * .value(); + * // => ['abc'] + */ + function thru(value, interceptor) { + return interceptor(value); + } + + /** + * This method is the wrapper version of `_.at`. + * + * @name at + * @memberOf _ + * @since 1.0.0 + * @category Seq + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _(object).at(['a[0].b.c', 'a[1]']).value(); + * // => [3, 4] + */ + var wrapperAt = flatRest(function(paths) { + var length = paths.length, + start = length ? paths[0] : 0, + value = this.__wrapped__, + interceptor = function(object) { return baseAt(object, paths); }; + + if (length > 1 || this.__actions__.length || + !(value instanceof LazyWrapper) || !isIndex(start)) { + return this.thru(interceptor); + } + value = value.slice(start, +start + (length ? 1 : 0)); + value.__actions__.push({ + 'func': thru, + 'args': [interceptor], + 'thisArg': undefined + }); + return new LodashWrapper(value, this.__chain__).thru(function(array) { + if (length && !array.length) { + array.push(undefined); + } + return array; + }); + }); + + /** + * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. + * + * @name chain + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // A sequence without explicit chaining. + * _(users).head(); + * // => { 'user': 'barney', 'age': 36 } + * + * // A sequence with explicit chaining. + * _(users) + * .chain() + * .head() + * .pick('user') + * .value(); + * // => { 'user': 'barney' } + */ + function wrapperChain() { + return chain(this); + } + + /** + * Executes the chain sequence and returns the wrapped result. + * + * @name commit + * @memberOf _ + * @since 3.2.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2]; + * var wrapped = _(array).push(3); + * + * console.log(array); + * // => [1, 2] + * + * wrapped = wrapped.commit(); + * console.log(array); + * // => [1, 2, 3] + * + * wrapped.last(); + * // => 3 + * + * console.log(array); + * // => [1, 2, 3] + */ + function wrapperCommit() { + return new LodashWrapper(this.value(), this.__chain__); + } + + /** + * Gets the next value on a wrapped object following the + * [iterator protocol](https://mdn.io/iteration_protocols#iterator). + * + * @name next + * @memberOf _ + * @since 4.0.0 + * @category Seq + * @returns {Object} Returns the next iterator value. + * @example + * + * var wrapped = _([1, 2]); + * + * wrapped.next(); + * // => { 'done': false, 'value': 1 } + * + * wrapped.next(); + * // => { 'done': false, 'value': 2 } + * + * wrapped.next(); + * // => { 'done': true, 'value': undefined } + */ + function wrapperNext() { + if (this.__values__ === undefined) { + this.__values__ = toArray(this.value()); + } + var done = this.__index__ >= this.__values__.length, + value = done ? undefined : this.__values__[this.__index__++]; + + return { 'done': done, 'value': value }; + } + + /** + * Enables the wrapper to be iterable. + * + * @name Symbol.iterator + * @memberOf _ + * @since 4.0.0 + * @category Seq + * @returns {Object} Returns the wrapper object. + * @example + * + * var wrapped = _([1, 2]); + * + * wrapped[Symbol.iterator]() === wrapped; + * // => true + * + * Array.from(wrapped); + * // => [1, 2] + */ + function wrapperToIterator() { + return this; + } + + /** + * Creates a clone of the chain sequence planting `value` as the wrapped value. + * + * @name plant + * @memberOf _ + * @since 3.2.0 + * @category Seq + * @param {*} value The value to plant. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var wrapped = _([1, 2]).map(square); + * var other = wrapped.plant([3, 4]); + * + * other.value(); + * // => [9, 16] + * + * wrapped.value(); + * // => [1, 4] + */ + function wrapperPlant(value) { + var result, + parent = this; + + while (parent instanceof baseLodash) { + var clone = wrapperClone(parent); + clone.__index__ = 0; + clone.__values__ = undefined; + if (result) { + previous.__wrapped__ = clone; + } else { + result = clone; + } + var previous = clone; + parent = parent.__wrapped__; + } + previous.__wrapped__ = value; + return result; + } + + /** + * This method is the wrapper version of `_.reverse`. + * + * **Note:** This method mutates the wrapped array. + * + * @name reverse + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2, 3]; + * + * _(array).reverse().value() + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function wrapperReverse() { + var value = this.__wrapped__; + if (value instanceof LazyWrapper) { + var wrapped = value; + if (this.__actions__.length) { + wrapped = new LazyWrapper(this); + } + wrapped = wrapped.reverse(); + wrapped.__actions__.push({ + 'func': thru, + 'args': [reverse], + 'thisArg': undefined + }); + return new LodashWrapper(wrapped, this.__chain__); + } + return this.thru(reverse); + } + + /** + * Executes the chain sequence to resolve the unwrapped value. + * + * @name value + * @memberOf _ + * @since 0.1.0 + * @alias toJSON, valueOf + * @category Seq + * @returns {*} Returns the resolved unwrapped value. + * @example + * + * _([1, 2, 3]).value(); + * // => [1, 2, 3] + */ + function wrapperValue() { + return baseWrapperValue(this.__wrapped__, this.__actions__); + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The corresponding value of + * each key is the number of times the key was returned by `iteratee`. The + * iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.countBy([6.1, 4.2, 6.3], Math.floor); + * // => { '4': 1, '6': 2 } + * + * // The `_.property` iteratee shorthand. + * _.countBy(['one', 'two', 'three'], 'length'); + * // => { '3': 2, '5': 1 } + */ + var countBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + ++result[key]; + } else { + baseAssignValue(result, key, 1); + } + }); + + /** + * Checks if `predicate` returns truthy for **all** elements of `collection`. + * Iteration is stopped once `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * **Note:** This method returns `true` for + * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because + * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of + * elements of empty collections. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * _.every([true, 1, null, 'yes'], Boolean); + * // => false + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.every(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.every(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.every(users, 'active'); + * // => false + */ + function every(collection, predicate, guard) { + var func = isArray(collection) ? arrayEvery : baseEvery; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Iterates over elements of `collection`, returning an array of all elements + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index|key, collection). + * + * **Note:** Unlike `_.remove`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @see _.reject + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * _.filter(users, function(o) { return !o.active; }); + * // => objects for ['fred'] + * + * // The `_.matches` iteratee shorthand. + * _.filter(users, { 'age': 36, 'active': true }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.filter(users, ['active', false]); + * // => objects for ['fred'] + * + * // The `_.property` iteratee shorthand. + * _.filter(users, 'active'); + * // => objects for ['barney'] + */ + function filter(collection, predicate) { + var func = isArray(collection) ? arrayFilter : baseFilter; + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Iterates over elements of `collection`, returning the first element + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false }, + * { 'user': 'pebbles', 'age': 1, 'active': true } + * ]; + * + * _.find(users, function(o) { return o.age < 40; }); + * // => object for 'barney' + * + * // The `_.matches` iteratee shorthand. + * _.find(users, { 'age': 1, 'active': true }); + * // => object for 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.find(users, ['active', false]); + * // => object for 'fred' + * + * // The `_.property` iteratee shorthand. + * _.find(users, 'active'); + * // => object for 'barney' + */ + var find = createFind(findIndex); + + /** + * This method is like `_.find` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Collection + * @param {Array|Object} collection The collection to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=collection.length-1] The index to search from. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * _.findLast([1, 2, 3, 4], function(n) { + * return n % 2 == 1; + * }); + * // => 3 + */ + var findLast = createFind(findLastIndex); + + /** + * Creates a flattened array of values by running each element in `collection` + * thru `iteratee` and flattening the mapped results. The iteratee is invoked + * with three arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [n, n]; + * } + * + * _.flatMap([1, 2], duplicate); + * // => [1, 1, 2, 2] + */ + function flatMap(collection, iteratee) { + return baseFlatten(map(collection, iteratee), 1); + } + + /** + * This method is like `_.flatMap` except that it recursively flattens the + * mapped results. + * + * @static + * @memberOf _ + * @since 4.7.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [[[n, n]]]; + * } + * + * _.flatMapDeep([1, 2], duplicate); + * // => [1, 1, 2, 2] + */ + function flatMapDeep(collection, iteratee) { + return baseFlatten(map(collection, iteratee), INFINITY); + } + + /** + * This method is like `_.flatMap` except that it recursively flattens the + * mapped results up to `depth` times. + * + * @static + * @memberOf _ + * @since 4.7.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {number} [depth=1] The maximum recursion depth. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [[[n, n]]]; + * } + * + * _.flatMapDepth([1, 2], duplicate, 2); + * // => [[1, 1], [2, 2]] + */ + function flatMapDepth(collection, iteratee, depth) { + depth = depth === undefined ? 1 : toInteger(depth); + return baseFlatten(map(collection, iteratee), depth); + } + + /** + * Iterates over elements of `collection` and invokes `iteratee` for each element. + * The iteratee is invoked with three arguments: (value, index|key, collection). + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * **Note:** As with other "Collections" methods, objects with a "length" + * property are iterated like arrays. To avoid this behavior use `_.forIn` + * or `_.forOwn` for object iteration. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @alias each + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @see _.forEachRight + * @example + * + * _.forEach([1, 2], function(value) { + * console.log(value); + * }); + * // => Logs `1` then `2`. + * + * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a' then 'b' (iteration order is not guaranteed). + */ + function forEach(collection, iteratee) { + var func = isArray(collection) ? arrayEach : baseEach; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.forEach` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @alias eachRight + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @see _.forEach + * @example + * + * _.forEachRight([1, 2], function(value) { + * console.log(value); + * }); + * // => Logs `2` then `1`. + */ + function forEachRight(collection, iteratee) { + var func = isArray(collection) ? arrayEachRight : baseEachRight; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The order of grouped values + * is determined by the order they occur in `collection`. The corresponding + * value of each key is an array of elements responsible for generating the + * key. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.groupBy([6.1, 4.2, 6.3], Math.floor); + * // => { '4': [4.2], '6': [6.1, 6.3] } + * + * // The `_.property` iteratee shorthand. + * _.groupBy(['one', 'two', 'three'], 'length'); + * // => { '3': ['one', 'two'], '5': ['three'] } + */ + var groupBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + result[key].push(value); + } else { + baseAssignValue(result, key, [value]); + } + }); + + /** + * Checks if `value` is in `collection`. If `collection` is a string, it's + * checked for a substring of `value`, otherwise + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * is used for equality comparisons. If `fromIndex` is negative, it's used as + * the offset from the end of `collection`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. + * @returns {boolean} Returns `true` if `value` is found, else `false`. + * @example + * + * _.includes([1, 2, 3], 1); + * // => true + * + * _.includes([1, 2, 3], 1, 2); + * // => false + * + * _.includes({ 'a': 1, 'b': 2 }, 1); + * // => true + * + * _.includes('abcd', 'bc'); + * // => true + */ + function includes(collection, value, fromIndex, guard) { + collection = isArrayLike(collection) ? collection : values(collection); + fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0; + + var length = collection.length; + if (fromIndex < 0) { + fromIndex = nativeMax(length + fromIndex, 0); + } + return isString(collection) + ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1) + : (!!length && baseIndexOf(collection, value, fromIndex) > -1); + } + + /** + * Invokes the method at `path` of each element in `collection`, returning + * an array of the results of each invoked method. Any additional arguments + * are provided to each invoked method. If `path` is a function, it's invoked + * for, and `this` bound to, each element in `collection`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Function|string} path The path of the method to invoke or + * the function invoked per iteration. + * @param {...*} [args] The arguments to invoke each method with. + * @returns {Array} Returns the array of results. + * @example + * + * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort'); + * // => [[1, 5, 7], [1, 2, 3]] + * + * _.invokeMap([123, 456], String.prototype.split, ''); + * // => [['1', '2', '3'], ['4', '5', '6']] + */ + var invokeMap = baseRest(function(collection, path, args) { + var index = -1, + isFunc = typeof path == 'function', + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value) { + result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args); + }); + return result; + }); + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The corresponding value of + * each key is the last element responsible for generating the key. The + * iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * var array = [ + * { 'dir': 'left', 'code': 97 }, + * { 'dir': 'right', 'code': 100 } + * ]; + * + * _.keyBy(array, function(o) { + * return String.fromCharCode(o.code); + * }); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + * + * _.keyBy(array, 'dir'); + * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } + */ + var keyBy = createAggregator(function(result, value, key) { + baseAssignValue(result, key, value); + }); + + /** + * Creates an array of values by running each element in `collection` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. + * + * The guarded methods are: + * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, + * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, + * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, + * `template`, `trim`, `trimEnd`, `trimStart`, and `words` + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + * @example + * + * function square(n) { + * return n * n; + * } + * + * _.map([4, 8], square); + * // => [16, 64] + * + * _.map({ 'a': 4, 'b': 8 }, square); + * // => [16, 64] (iteration order is not guaranteed) + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * // The `_.property` iteratee shorthand. + * _.map(users, 'user'); + * // => ['barney', 'fred'] + */ + function map(collection, iteratee) { + var func = isArray(collection) ? arrayMap : baseMap; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.sortBy` except that it allows specifying the sort + * orders of the iteratees to sort by. If `orders` is unspecified, all values + * are sorted in ascending order. Otherwise, specify an order of "desc" for + * descending or "asc" for ascending sort order of corresponding values. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]] + * The iteratees to sort by. + * @param {string[]} [orders] The sort orders of `iteratees`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 34 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 36 } + * ]; + * + * // Sort by `user` in ascending order and by `age` in descending order. + * _.orderBy(users, ['user', 'age'], ['asc', 'desc']); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + */ + function orderBy(collection, iteratees, orders, guard) { + if (collection == null) { + return []; + } + if (!isArray(iteratees)) { + iteratees = iteratees == null ? [] : [iteratees]; + } + orders = guard ? undefined : orders; + if (!isArray(orders)) { + orders = orders == null ? [] : [orders]; + } + return baseOrderBy(collection, iteratees, orders); + } + + /** + * Creates an array of elements split into two groups, the first of which + * contains elements `predicate` returns truthy for, the second of which + * contains elements `predicate` returns falsey for. The predicate is + * invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the array of grouped elements. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * _.partition(users, function(o) { return o.active; }); + * // => objects for [['fred'], ['barney', 'pebbles']] + * + * // The `_.matches` iteratee shorthand. + * _.partition(users, { 'age': 1, 'active': false }); + * // => objects for [['pebbles'], ['barney', 'fred']] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.partition(users, ['active', false]); + * // => objects for [['barney', 'pebbles'], ['fred']] + * + * // The `_.property` iteratee shorthand. + * _.partition(users, 'active'); + * // => objects for [['fred'], ['barney', 'pebbles']] + */ + var partition = createAggregator(function(result, value, key) { + result[key ? 0 : 1].push(value); + }, function() { return [[], []]; }); + + /** + * Reduces `collection` to a value which is the accumulated result of running + * each element in `collection` thru `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not given, the first element of `collection` is used as the initial + * value. The iteratee is invoked with four arguments: + * (accumulator, value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.reduce`, `_.reduceRight`, and `_.transform`. + * + * The guarded methods are: + * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, + * and `sortBy` + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @see _.reduceRight + * @example + * + * _.reduce([1, 2], function(sum, n) { + * return sum + n; + * }, 0); + * // => 3 + * + * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { + * (result[value] || (result[value] = [])).push(key); + * return result; + * }, {}); + * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) + */ + function reduce(collection, iteratee, accumulator) { + var func = isArray(collection) ? arrayReduce : baseReduce, + initAccum = arguments.length < 3; + + return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach); + } + + /** + * This method is like `_.reduce` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @see _.reduce + * @example + * + * var array = [[0, 1], [2, 3], [4, 5]]; + * + * _.reduceRight(array, function(flattened, other) { + * return flattened.concat(other); + * }, []); + * // => [4, 5, 2, 3, 0, 1] + */ + function reduceRight(collection, iteratee, accumulator) { + var func = isArray(collection) ? arrayReduceRight : baseReduce, + initAccum = arguments.length < 3; + + return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight); + } + + /** + * The opposite of `_.filter`; this method returns the elements of `collection` + * that `predicate` does **not** return truthy for. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @see _.filter + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * _.reject(users, function(o) { return !o.active; }); + * // => objects for ['fred'] + * + * // The `_.matches` iteratee shorthand. + * _.reject(users, { 'age': 40, 'active': true }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.reject(users, ['active', false]); + * // => objects for ['fred'] + * + * // The `_.property` iteratee shorthand. + * _.reject(users, 'active'); + * // => objects for ['barney'] + */ + function reject(collection, predicate) { + var func = isArray(collection) ? arrayFilter : baseFilter; + return func(collection, negate(getIteratee(predicate, 3))); + } + + /** + * Gets a random element from `collection`. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Collection + * @param {Array|Object} collection The collection to sample. + * @returns {*} Returns the random element. + * @example + * + * _.sample([1, 2, 3, 4]); + * // => 2 + */ + function sample(collection) { + var func = isArray(collection) ? arraySample : baseSample; + return func(collection); + } + + /** + * Gets `n` random elements at unique keys from `collection` up to the + * size of `collection`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to sample. + * @param {number} [n=1] The number of elements to sample. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the random elements. + * @example + * + * _.sampleSize([1, 2, 3], 2); + * // => [3, 1] + * + * _.sampleSize([1, 2, 3], 4); + * // => [2, 3, 1] + */ + function sampleSize(collection, n, guard) { + if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) { + n = 1; + } else { + n = toInteger(n); + } + var func = isArray(collection) ? arraySampleSize : baseSampleSize; + return func(collection, n); + } + + /** + * Creates an array of shuffled values, using a version of the + * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + * @example + * + * _.shuffle([1, 2, 3, 4]); + * // => [4, 1, 3, 2] + */ + function shuffle(collection) { + var func = isArray(collection) ? arrayShuffle : baseShuffle; + return func(collection); + } + + /** + * Gets the size of `collection` by returning its length for array-like + * values or the number of own enumerable string keyed properties for objects. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the collection size. + * @example + * + * _.size([1, 2, 3]); + * // => 3 + * + * _.size({ 'a': 1, 'b': 2 }); + * // => 2 + * + * _.size('pebbles'); + * // => 7 + */ + function size(collection) { + if (collection == null) { + return 0; + } + if (isArrayLike(collection)) { + return isString(collection) ? stringSize(collection) : collection.length; + } + var tag = getTag(collection); + if (tag == mapTag || tag == setTag) { + return collection.size; + } + return baseKeys(collection).length; + } + + /** + * Checks if `predicate` returns truthy for **any** element of `collection`. + * Iteration is stopped once `predicate` returns truthy. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + * @example + * + * _.some([null, 0, 'yes', false], Boolean); + * // => true + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.some(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.some(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.some(users, 'active'); + * // => true + */ + function some(collection, predicate, guard) { + var func = isArray(collection) ? arraySome : baseSome; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Creates an array of elements, sorted in ascending order by the results of + * running each element in a collection thru each iteratee. This method + * performs a stable sort, that is, it preserves the original sort order of + * equal elements. The iteratees are invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {...(Function|Function[])} [iteratees=[_.identity]] + * The iteratees to sort by. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 34 } + * ]; + * + * _.sortBy(users, [function(o) { return o.user; }]); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + * + * _.sortBy(users, ['user', 'age']); + * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] + */ + var sortBy = baseRest(function(collection, iteratees) { + if (collection == null) { + return []; + } + var length = iteratees.length; + if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { + iteratees = []; + } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { + iteratees = [iteratees[0]]; + } + return baseOrderBy(collection, baseFlatten(iteratees, 1), []); + }); + + /*------------------------------------------------------------------------*/ + + /** + * Gets the timestamp of the number of milliseconds that have elapsed since + * the Unix epoch (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Date + * @returns {number} Returns the timestamp. + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => Logs the number of milliseconds it took for the deferred invocation. + */ + var now = ctxNow || function() { + return root.Date.now(); + }; + + /*------------------------------------------------------------------------*/ + + /** + * The opposite of `_.before`; this method creates a function that invokes + * `func` once it's called `n` or more times. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {number} n The number of calls before `func` is invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var saves = ['profile', 'settings']; + * + * var done = _.after(saves.length, function() { + * console.log('done saving!'); + * }); + * + * _.forEach(saves, function(type) { + * asyncSave({ 'type': type, 'complete': done }); + * }); + * // => Logs 'done saving!' after the two async saves have completed. + */ + function after(n, func) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + n = toInteger(n); + return function() { + if (--n < 1) { + return func.apply(this, arguments); + } + }; + } + + /** + * Creates a function that invokes `func`, with up to `n` arguments, + * ignoring any additional arguments. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to cap arguments for. + * @param {number} [n=func.length] The arity cap. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new capped function. + * @example + * + * _.map(['6', '8', '10'], _.ary(parseInt, 1)); + * // => [6, 8, 10] + */ + function ary(func, n, guard) { + n = guard ? undefined : n; + n = (func && n == null) ? func.length : n; + return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n); + } + + /** + * Creates a function that invokes `func`, with the `this` binding and arguments + * of the created function, while it's called less than `n` times. Subsequent + * calls to the created function return the result of the last `func` invocation. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {number} n The number of calls at which `func` is no longer invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * jQuery(element).on('click', _.before(5, addContactToList)); + * // => Allows adding up to 4 contacts to the list. + */ + function before(n, func) { + var result; + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + n = toInteger(n); + return function() { + if (--n > 0) { + result = func.apply(this, arguments); + } + if (n <= 1) { + func = undefined; + } + return result; + }; + } + + /** + * Creates a function that invokes `func` with the `this` binding of `thisArg` + * and `partials` prepended to the arguments it receives. + * + * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for partially applied arguments. + * + * **Note:** Unlike native `Function#bind`, this method doesn't set the "length" + * property of bound functions. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * function greet(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * + * var object = { 'user': 'fred' }; + * + * var bound = _.bind(greet, object, 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * // Bound with placeholders. + * var bound = _.bind(greet, object, _, '!'); + * bound('hi'); + * // => 'hi fred!' + */ + var bind = baseRest(function(func, thisArg, partials) { + var bitmask = WRAP_BIND_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, getHolder(bind)); + bitmask |= WRAP_PARTIAL_FLAG; + } + return createWrap(func, bitmask, thisArg, partials, holders); + }); + + /** + * Creates a function that invokes the method at `object[key]` with `partials` + * prepended to the arguments it receives. + * + * This method differs from `_.bind` by allowing bound functions to reference + * methods that may be redefined or don't yet exist. See + * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) + * for more details. + * + * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * @static + * @memberOf _ + * @since 0.10.0 + * @category Function + * @param {Object} object The object to invoke the method on. + * @param {string} key The key of the method. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var object = { + * 'user': 'fred', + * 'greet': function(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * }; + * + * var bound = _.bindKey(object, 'greet', 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * object.greet = function(greeting, punctuation) { + * return greeting + 'ya ' + this.user + punctuation; + * }; + * + * bound('!'); + * // => 'hiya fred!' + * + * // Bound with placeholders. + * var bound = _.bindKey(object, 'greet', _, '!'); + * bound('hi'); + * // => 'hiya fred!' + */ + var bindKey = baseRest(function(object, key, partials) { + var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, getHolder(bindKey)); + bitmask |= WRAP_PARTIAL_FLAG; + } + return createWrap(key, bitmask, object, partials, holders); + }); + + /** + * Creates a function that accepts arguments of `func` and either invokes + * `func` returning its result, if at least `arity` number of arguments have + * been provided, or returns a function that accepts the remaining `func` + * arguments, and so on. The arity of `func` may be specified if `func.length` + * is not sufficient. + * + * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for provided arguments. + * + * **Note:** This method doesn't set the "length" property of curried functions. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curry(abc); + * + * curried(1)(2)(3); + * // => [1, 2, 3] + * + * curried(1, 2)(3); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // Curried with placeholders. + * curried(1)(_, 3)(2); + * // => [1, 2, 3] + */ + function curry(func, arity, guard) { + arity = guard ? undefined : arity; + var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curry.placeholder; + return result; + } + + /** + * This method is like `_.curry` except that arguments are applied to `func` + * in the manner of `_.partialRight` instead of `_.partial`. + * + * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for provided arguments. + * + * **Note:** This method doesn't set the "length" property of curried functions. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curryRight(abc); + * + * curried(3)(2)(1); + * // => [1, 2, 3] + * + * curried(2, 3)(1); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // Curried with placeholders. + * curried(3)(1, _)(2); + * // => [1, 2, 3] + */ + function curryRight(func, arity, guard) { + arity = guard ? undefined : arity; + var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curryRight.placeholder; + return result; + } + + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed `func` invocations and a `flush` method to immediately invoke them. + * Provide `options` to indicate whether `func` should be invoked on the + * leading and/or trailing edge of the `wait` timeout. The `func` is invoked + * with the last arguments provided to the debounced function. Subsequent + * calls to the debounced function return the result of the last `func` + * invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the debounced function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=false] + * Specify invoking on the leading edge of the timeout. + * @param {number} [options.maxWait] + * The maximum time `func` is allowed to be delayed before it's invoked. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // Avoid costly calculations while the window size is in flux. + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // Invoke `sendMail` when clicked, debouncing subsequent calls. + * jQuery(element).on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // Ensure `batchLog` is invoked once after 1 second of debounced calls. + * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); + * var source = new EventSource('/stream'); + * jQuery(source).on('message', debounced); + * + * // Cancel the trailing debounced invocation. + * jQuery(window).on('popstate', debounced.cancel); + */ + function debounce(func, wait, options) { + var lastArgs, + lastThis, + maxWait, + result, + timerId, + lastCallTime, + lastInvokeTime = 0, + leading = false, + maxing = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = toNumber(wait) || 0; + if (isObject(options)) { + leading = !!options.leading; + maxing = 'maxWait' in options; + maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + + function invokeFunc(time) { + var args = lastArgs, + thisArg = lastThis; + + lastArgs = lastThis = undefined; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; + } + + function leadingEdge(time) { + // Reset any `maxWait` timer. + lastInvokeTime = time; + // Start the timer for the trailing edge. + timerId = setTimeout(timerExpired, wait); + // Invoke the leading edge. + return leading ? invokeFunc(time) : result; + } + + function remainingWait(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime, + timeWaiting = wait - timeSinceLastCall; + + return maxing + ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) + : timeWaiting; + } + + function shouldInvoke(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime; + + // Either this is the first call, activity has stopped and we're at the + // trailing edge, the system time has gone backwards and we're treating + // it as the trailing edge, or we've hit the `maxWait` limit. + return (lastCallTime === undefined || (timeSinceLastCall >= wait) || + (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); + } + + function timerExpired() { + var time = now(); + if (shouldInvoke(time)) { + return trailingEdge(time); + } + // Restart the timer. + timerId = setTimeout(timerExpired, remainingWait(time)); + } + + function trailingEdge(time) { + timerId = undefined; + + // Only invoke if we have `lastArgs` which means `func` has been + // debounced at least once. + if (trailing && lastArgs) { + return invokeFunc(time); + } + lastArgs = lastThis = undefined; + return result; + } + + function cancel() { + if (timerId !== undefined) { + clearTimeout(timerId); + } + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = undefined; + } + + function flush() { + return timerId === undefined ? result : trailingEdge(now()); + } + + function debounced() { + var time = now(), + isInvoking = shouldInvoke(time); + + lastArgs = arguments; + lastThis = this; + lastCallTime = time; + + if (isInvoking) { + if (timerId === undefined) { + return leadingEdge(lastCallTime); + } + if (maxing) { + // Handle invocations in a tight loop. + timerId = setTimeout(timerExpired, wait); + return invokeFunc(lastCallTime); + } + } + if (timerId === undefined) { + timerId = setTimeout(timerExpired, wait); + } + return result; + } + debounced.cancel = cancel; + debounced.flush = flush; + return debounced; + } + + /** + * Defers invoking the `func` until the current call stack has cleared. Any + * additional arguments are provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to defer. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * @example + * + * _.defer(function(text) { + * console.log(text); + * }, 'deferred'); + * // => Logs 'deferred' after one millisecond. + */ + var defer = baseRest(function(func, args) { + return baseDelay(func, 1, args); + }); + + /** + * Invokes `func` after `wait` milliseconds. Any additional arguments are + * provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * @example + * + * _.delay(function(text) { + * console.log(text); + * }, 1000, 'later'); + * // => Logs 'later' after one second. + */ + var delay = baseRest(function(func, wait, args) { + return baseDelay(func, toNumber(wait) || 0, args); + }); + + /** + * Creates a function that invokes `func` with arguments reversed. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to flip arguments for. + * @returns {Function} Returns the new flipped function. + * @example + * + * var flipped = _.flip(function() { + * return _.toArray(arguments); + * }); + * + * flipped('a', 'b', 'c', 'd'); + * // => ['d', 'c', 'b', 'a'] + */ + function flip(func) { + return createWrap(func, WRAP_FLIP_FLAG); + } + + /** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided, it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is used as the map cache key. The `func` + * is invoked with the `this` binding of the memoized function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the + * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoized function. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * var other = { 'c': 3, 'd': 4 }; + * + * var values = _.memoize(_.values); + * values(object); + * // => [1, 2] + * + * values(other); + * // => [3, 4] + * + * object.a = 2; + * values(object); + * // => [1, 2] + * + * // Modify the result cache. + * values.cache.set(object, ['a', 'b']); + * values(object); + * // => ['a', 'b'] + * + * // Replace `_.memoize.Cache`. + * _.memoize.Cache = WeakMap; + */ + function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; + } + + // Expose `MapCache`. + memoize.Cache = MapCache; + + /** + * Creates a function that negates the result of the predicate `func`. The + * `func` predicate is invoked with the `this` binding and arguments of the + * created function. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} predicate The predicate to negate. + * @returns {Function} Returns the new negated function. + * @example + * + * function isEven(n) { + * return n % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ + function negate(predicate) { + if (typeof predicate != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + var args = arguments; + switch (args.length) { + case 0: return !predicate.call(this); + case 1: return !predicate.call(this, args[0]); + case 2: return !predicate.call(this, args[0], args[1]); + case 3: return !predicate.call(this, args[0], args[1], args[2]); + } + return !predicate.apply(this, args); + }; + } + + /** + * Creates a function that is restricted to invoking `func` once. Repeat calls + * to the function return the value of the first invocation. The `func` is + * invoked with the `this` binding and arguments of the created function. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var initialize = _.once(createApplication); + * initialize(); + * initialize(); + * // => `createApplication` is invoked once + */ + function once(func) { + return before(2, func); + } + + /** + * Creates a function that invokes `func` with its arguments transformed. + * + * @static + * @since 4.0.0 + * @memberOf _ + * @category Function + * @param {Function} func The function to wrap. + * @param {...(Function|Function[])} [transforms=[_.identity]] + * The argument transforms. + * @returns {Function} Returns the new function. + * @example + * + * function doubled(n) { + * return n * 2; + * } + * + * function square(n) { + * return n * n; + * } + * + * var func = _.overArgs(function(x, y) { + * return [x, y]; + * }, [square, doubled]); + * + * func(9, 3); + * // => [81, 6] + * + * func(10, 5); + * // => [100, 10] + */ + var overArgs = castRest(function(func, transforms) { + transforms = (transforms.length == 1 && isArray(transforms[0])) + ? arrayMap(transforms[0], baseUnary(getIteratee())) + : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee())); + + var funcsLength = transforms.length; + return baseRest(function(args) { + var index = -1, + length = nativeMin(args.length, funcsLength); + + while (++index < length) { + args[index] = transforms[index].call(this, args[index]); + } + return apply(func, this, args); + }); + }); + + /** + * Creates a function that invokes `func` with `partials` prepended to the + * arguments it receives. This method is like `_.bind` except it does **not** + * alter the `this` binding. + * + * The `_.partial.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method doesn't set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @since 0.2.0 + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * function greet(greeting, name) { + * return greeting + ' ' + name; + * } + * + * var sayHelloTo = _.partial(greet, 'hello'); + * sayHelloTo('fred'); + * // => 'hello fred' + * + * // Partially applied with placeholders. + * var greetFred = _.partial(greet, _, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + */ + var partial = baseRest(function(func, partials) { + var holders = replaceHolders(partials, getHolder(partial)); + return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders); + }); + + /** + * This method is like `_.partial` except that partially applied arguments + * are appended to the arguments it receives. + * + * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method doesn't set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * function greet(greeting, name) { + * return greeting + ' ' + name; + * } + * + * var greetFred = _.partialRight(greet, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + * + * // Partially applied with placeholders. + * var sayHelloTo = _.partialRight(greet, 'hello', _); + * sayHelloTo('fred'); + * // => 'hello fred' + */ + var partialRight = baseRest(function(func, partials) { + var holders = replaceHolders(partials, getHolder(partialRight)); + return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders); + }); + + /** + * Creates a function that invokes `func` with arguments arranged according + * to the specified `indexes` where the argument value at the first index is + * provided as the first argument, the argument value at the second index is + * provided as the second argument, and so on. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to rearrange arguments for. + * @param {...(number|number[])} indexes The arranged argument indexes. + * @returns {Function} Returns the new function. + * @example + * + * var rearged = _.rearg(function(a, b, c) { + * return [a, b, c]; + * }, [2, 0, 1]); + * + * rearged('b', 'c', 'a') + * // => ['a', 'b', 'c'] + */ + var rearg = flatRest(function(func, indexes) { + return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes); + }); + + /** + * Creates a function that invokes `func` with the `this` binding of the + * created function and arguments from `start` and beyond provided as + * an array. + * + * **Note:** This method is based on the + * [rest parameter](https://mdn.io/rest_parameters). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.rest(function(what, names) { + * return what + ' ' + _.initial(names).join(', ') + + * (_.size(names) > 1 ? ', & ' : '') + _.last(names); + * }); + * + * say('hello', 'fred', 'barney', 'pebbles'); + * // => 'hello fred, barney, & pebbles' + */ + function rest(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = start === undefined ? start : toInteger(start); + return baseRest(func, start); + } + + /** + * Creates a function that invokes `func` with the `this` binding of the + * create function and an array of arguments much like + * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply). + * + * **Note:** This method is based on the + * [spread operator](https://mdn.io/spread_operator). + * + * @static + * @memberOf _ + * @since 3.2.0 + * @category Function + * @param {Function} func The function to spread arguments over. + * @param {number} [start=0] The start position of the spread. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.spread(function(who, what) { + * return who + ' says ' + what; + * }); + * + * say(['fred', 'hello']); + * // => 'fred says hello' + * + * var numbers = Promise.all([ + * Promise.resolve(40), + * Promise.resolve(36) + * ]); + * + * numbers.then(_.spread(function(x, y) { + * return x + y; + * })); + * // => a Promise of 76 + */ + function spread(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = start == null ? 0 : nativeMax(toInteger(start), 0); + return baseRest(function(args) { + var array = args[start], + otherArgs = castSlice(args, 0, start); + + if (array) { + arrayPush(otherArgs, array); + } + return apply(func, this, otherArgs); + }); + } + + /** + * Creates a throttled function that only invokes `func` at most once per + * every `wait` milliseconds. The throttled function comes with a `cancel` + * method to cancel delayed `func` invocations and a `flush` method to + * immediately invoke them. Provide `options` to indicate whether `func` + * should be invoked on the leading and/or trailing edge of the `wait` + * timeout. The `func` is invoked with the last arguments provided to the + * throttled function. Subsequent calls to the throttled function return the + * result of the last `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the throttled function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.throttle` and `_.debounce`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to throttle. + * @param {number} [wait=0] The number of milliseconds to throttle invocations to. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=true] + * Specify invoking on the leading edge of the timeout. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // Avoid excessively updating the position while scrolling. + * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); + * + * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. + * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); + * jQuery(element).on('click', throttled); + * + * // Cancel the trailing throttled invocation. + * jQuery(window).on('popstate', throttled.cancel); + */ + function throttle(func, wait, options) { + var leading = true, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (isObject(options)) { + leading = 'leading' in options ? !!options.leading : leading; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + return debounce(func, wait, { + 'leading': leading, + 'maxWait': wait, + 'trailing': trailing + }); + } + + /** + * Creates a function that accepts up to one argument, ignoring any + * additional arguments. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + * @example + * + * _.map(['6', '8', '10'], _.unary(parseInt)); + * // => [6, 8, 10] + */ + function unary(func) { + return ary(func, 1); + } + + /** + * Creates a function that provides `value` to `wrapper` as its first + * argument. Any additional arguments provided to the function are appended + * to those provided to the `wrapper`. The wrapper is invoked with the `this` + * binding of the created function. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {*} value The value to wrap. + * @param {Function} [wrapper=identity] The wrapper function. + * @returns {Function} Returns the new function. + * @example + * + * var p = _.wrap(_.escape, function(func, text) { + * return '

' + func(text) + '

'; + * }); + * + * p('fred, barney, & pebbles'); + * // => '

fred, barney, & pebbles

' + */ + function wrap(value, wrapper) { + return partial(castFunction(wrapper), value); + } + + /*------------------------------------------------------------------------*/ + + /** + * Casts `value` as an array if it's not one. + * + * @static + * @memberOf _ + * @since 4.4.0 + * @category Lang + * @param {*} value The value to inspect. + * @returns {Array} Returns the cast array. + * @example + * + * _.castArray(1); + * // => [1] + * + * _.castArray({ 'a': 1 }); + * // => [{ 'a': 1 }] + * + * _.castArray('abc'); + * // => ['abc'] + * + * _.castArray(null); + * // => [null] + * + * _.castArray(undefined); + * // => [undefined] + * + * _.castArray(); + * // => [] + * + * var array = [1, 2, 3]; + * console.log(_.castArray(array) === array); + * // => true + */ + function castArray() { + if (!arguments.length) { + return []; + } + var value = arguments[0]; + return isArray(value) ? value : [value]; + } + + /** + * Creates a shallow clone of `value`. + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) + * and supports cloning arrays, array buffers, booleans, date objects, maps, + * numbers, `Object` objects, regexes, sets, strings, symbols, and typed + * arrays. The own enumerable properties of `arguments` objects are cloned + * as plain objects. An empty object is returned for uncloneable values such + * as error objects, functions, DOM nodes, and WeakMaps. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to clone. + * @returns {*} Returns the cloned value. + * @see _.cloneDeep + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var shallow = _.clone(objects); + * console.log(shallow[0] === objects[0]); + * // => true + */ + function clone(value) { + return baseClone(value, CLONE_SYMBOLS_FLAG); + } + + /** + * This method is like `_.clone` except that it accepts `customizer` which + * is invoked to produce the cloned value. If `customizer` returns `undefined`, + * cloning is handled by the method instead. The `customizer` is invoked with + * up to four arguments; (value [, index|key, object, stack]). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to clone. + * @param {Function} [customizer] The function to customize cloning. + * @returns {*} Returns the cloned value. + * @see _.cloneDeepWith + * @example + * + * function customizer(value) { + * if (_.isElement(value)) { + * return value.cloneNode(false); + * } + * } + * + * var el = _.cloneWith(document.body, customizer); + * + * console.log(el === document.body); + * // => false + * console.log(el.nodeName); + * // => 'BODY' + * console.log(el.childNodes.length); + * // => 0 + */ + function cloneWith(value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseClone(value, CLONE_SYMBOLS_FLAG, customizer); + } + + /** + * This method is like `_.clone` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Lang + * @param {*} value The value to recursively clone. + * @returns {*} Returns the deep cloned value. + * @see _.clone + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var deep = _.cloneDeep(objects); + * console.log(deep[0] === objects[0]); + * // => false + */ + function cloneDeep(value) { + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); + } + + /** + * This method is like `_.cloneWith` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to recursively clone. + * @param {Function} [customizer] The function to customize cloning. + * @returns {*} Returns the deep cloned value. + * @see _.cloneWith + * @example + * + * function customizer(value) { + * if (_.isElement(value)) { + * return value.cloneNode(true); + * } + * } + * + * var el = _.cloneDeepWith(document.body, customizer); + * + * console.log(el === document.body); + * // => false + * console.log(el.nodeName); + * // => 'BODY' + * console.log(el.childNodes.length); + * // => 20 + */ + function cloneDeepWith(value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer); + } + + /** + * Checks if `object` conforms to `source` by invoking the predicate + * properties of `source` with the corresponding property values of `object`. + * + * **Note:** This method is equivalent to `_.conforms` when `source` is + * partially applied. + * + * @static + * @memberOf _ + * @since 4.14.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property predicates to conform to. + * @returns {boolean} Returns `true` if `object` conforms, else `false`. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * + * _.conformsTo(object, { 'b': function(n) { return n > 1; } }); + * // => true + * + * _.conformsTo(object, { 'b': function(n) { return n > 2; } }); + * // => false + */ + function conformsTo(object, source) { + return source == null || baseConformsTo(object, source, keys(source)); + } + + /** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ + function eq(value, other) { + return value === other || (value !== value && other !== other); + } + + /** + * Checks if `value` is greater than `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than `other`, + * else `false`. + * @see _.lt + * @example + * + * _.gt(3, 1); + * // => true + * + * _.gt(3, 3); + * // => false + * + * _.gt(1, 3); + * // => false + */ + var gt = createRelationalOperation(baseGt); + + /** + * Checks if `value` is greater than or equal to `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than or equal to + * `other`, else `false`. + * @see _.lte + * @example + * + * _.gte(3, 1); + * // => true + * + * _.gte(3, 3); + * // => true + * + * _.gte(1, 3); + * // => false + */ + var gte = createRelationalOperation(function(value, other) { + return value >= other; + }); + + /** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ + var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); + }; + + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ + var isArray = Array.isArray; + + /** + * Checks if `value` is classified as an `ArrayBuffer` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. + * @example + * + * _.isArrayBuffer(new ArrayBuffer(2)); + * // => true + * + * _.isArrayBuffer(new Array(2)); + * // => false + */ + var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer; + + /** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ + function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); + } + + /** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ + function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike(value); + } + + /** + * Checks if `value` is classified as a boolean primitive or object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. + * @example + * + * _.isBoolean(false); + * // => true + * + * _.isBoolean(null); + * // => false + */ + function isBoolean(value) { + return value === true || value === false || + (isObjectLike(value) && baseGetTag(value) == boolTag); + } + + /** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ + var isBuffer = nativeIsBuffer || stubFalse; + + /** + * Checks if `value` is classified as a `Date` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + * @example + * + * _.isDate(new Date); + * // => true + * + * _.isDate('Mon April 23 2012'); + * // => false + */ + var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; + + /** + * Checks if `value` is likely a DOM element. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. + * @example + * + * _.isElement(document.body); + * // => true + * + * _.isElement(''); + * // => false + */ + function isElement(value) { + return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value); + } + + /** + * Checks if `value` is an empty object, collection, map, or set. + * + * Objects are considered empty if they have no own enumerable string keyed + * properties. + * + * Array-like values such as `arguments` objects, arrays, buffers, strings, or + * jQuery-like collections are considered empty if they have a `length` of `0`. + * Similarly, maps and sets are considered empty if they have a `size` of `0`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * _.isEmpty(null); + * // => true + * + * _.isEmpty(true); + * // => true + * + * _.isEmpty(1); + * // => true + * + * _.isEmpty([1, 2, 3]); + * // => false + * + * _.isEmpty({ 'a': 1 }); + * // => false + */ + function isEmpty(value) { + if (value == null) { + return true; + } + if (isArrayLike(value) && + (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || + isBuffer(value) || isTypedArray(value) || isArguments(value))) { + return !value.length; + } + var tag = getTag(value); + if (tag == mapTag || tag == setTag) { + return !value.size; + } + if (isPrototype(value)) { + return !baseKeys(value).length; + } + for (var key in value) { + if (hasOwnProperty.call(value, key)) { + return false; + } + } + return true; + } + + /** + * Performs a deep comparison between two values to determine if they are + * equivalent. + * + * **Note:** This method supports comparing arrays, array buffers, booleans, + * date objects, error objects, maps, numbers, `Object` objects, regexes, + * sets, strings, symbols, and typed arrays. `Object` objects are compared + * by their own, not inherited, enumerable properties. Functions and DOM + * nodes are compared by strict equality, i.e. `===`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.isEqual(object, other); + * // => true + * + * object === other; + * // => false + */ + function isEqual(value, other) { + return baseIsEqual(value, other); + } + + /** + * This method is like `_.isEqual` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined`, comparisons + * are handled by the method instead. The `customizer` is invoked with up to + * six arguments: (objValue, othValue [, index|key, object, other, stack]). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * function isGreeting(value) { + * return /^h(?:i|ello)$/.test(value); + * } + * + * function customizer(objValue, othValue) { + * if (isGreeting(objValue) && isGreeting(othValue)) { + * return true; + * } + * } + * + * var array = ['hello', 'goodbye']; + * var other = ['hi', 'goodbye']; + * + * _.isEqualWith(array, other, customizer); + * // => true + */ + function isEqualWith(value, other, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + var result = customizer ? customizer(value, other) : undefined; + return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result; + } + + /** + * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, + * `SyntaxError`, `TypeError`, or `URIError` object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an error object, else `false`. + * @example + * + * _.isError(new Error); + * // => true + * + * _.isError(Error); + * // => false + */ + function isError(value) { + if (!isObjectLike(value)) { + return false; + } + var tag = baseGetTag(value); + return tag == errorTag || tag == domExcTag || + (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value)); + } + + /** + * Checks if `value` is a finite primitive number. + * + * **Note:** This method is based on + * [`Number.isFinite`](https://mdn.io/Number/isFinite). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. + * @example + * + * _.isFinite(3); + * // => true + * + * _.isFinite(Number.MIN_VALUE); + * // => true + * + * _.isFinite(Infinity); + * // => false + * + * _.isFinite('3'); + * // => false + */ + function isFinite(value) { + return typeof value == 'number' && nativeIsFinite(value); + } + + /** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ + function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; + } + + /** + * Checks if `value` is an integer. + * + * **Note:** This method is based on + * [`Number.isInteger`](https://mdn.io/Number/isInteger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an integer, else `false`. + * @example + * + * _.isInteger(3); + * // => true + * + * _.isInteger(Number.MIN_VALUE); + * // => false + * + * _.isInteger(Infinity); + * // => false + * + * _.isInteger('3'); + * // => false + */ + function isInteger(value) { + return typeof value == 'number' && value == toInteger(value); + } + + /** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ + function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ + function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); + } + + /** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ + function isObjectLike(value) { + return value != null && typeof value == 'object'; + } + + /** + * Checks if `value` is classified as a `Map` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + * @example + * + * _.isMap(new Map); + * // => true + * + * _.isMap(new WeakMap); + * // => false + */ + var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; + + /** + * Performs a partial deep comparison between `object` and `source` to + * determine if `object` contains equivalent property values. + * + * **Note:** This method is equivalent to `_.matches` when `source` is + * partially applied. + * + * Partial comparisons will match empty array and empty object `source` + * values against any array or object value, respectively. See `_.isEqual` + * for a list of supported value comparisons. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * + * _.isMatch(object, { 'b': 2 }); + * // => true + * + * _.isMatch(object, { 'b': 1 }); + * // => false + */ + function isMatch(object, source) { + return object === source || baseIsMatch(object, source, getMatchData(source)); + } + + /** + * This method is like `_.isMatch` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined`, comparisons + * are handled by the method instead. The `customizer` is invoked with five + * arguments: (objValue, srcValue, index|key, object, source). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * function isGreeting(value) { + * return /^h(?:i|ello)$/.test(value); + * } + * + * function customizer(objValue, srcValue) { + * if (isGreeting(objValue) && isGreeting(srcValue)) { + * return true; + * } + * } + * + * var object = { 'greeting': 'hello' }; + * var source = { 'greeting': 'hi' }; + * + * _.isMatchWith(object, source, customizer); + * // => true + */ + function isMatchWith(object, source, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseIsMatch(object, source, getMatchData(source), customizer); + } + + /** + * Checks if `value` is `NaN`. + * + * **Note:** This method is based on + * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as + * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for + * `undefined` and other non-number values. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ + function isNaN(value) { + // An `NaN` primitive is the only value that is not equal to itself. + // Perform the `toStringTag` check first to avoid errors with some + // ActiveX objects in IE. + return isNumber(value) && value != +value; + } + + /** + * Checks if `value` is a pristine native function. + * + * **Note:** This method can't reliably detect native functions in the presence + * of the core-js package because core-js circumvents this kind of detection. + * Despite multiple requests, the core-js maintainer has made it clear: any + * attempt to fix the detection will be obstructed. As a result, we're left + * with little choice but to throw an error. Unfortunately, this also affects + * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill), + * which rely on core-js. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ + function isNative(value) { + if (isMaskable(value)) { + throw new Error(CORE_ERROR_TEXT); + } + return baseIsNative(value); + } + + /** + * Checks if `value` is `null`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `null`, else `false`. + * @example + * + * _.isNull(null); + * // => true + * + * _.isNull(void 0); + * // => false + */ + function isNull(value) { + return value === null; + } + + /** + * Checks if `value` is `null` or `undefined`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is nullish, else `false`. + * @example + * + * _.isNil(null); + * // => true + * + * _.isNil(void 0); + * // => true + * + * _.isNil(NaN); + * // => false + */ + function isNil(value) { + return value == null; + } + + /** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are + * classified as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a number, else `false`. + * @example + * + * _.isNumber(3); + * // => true + * + * _.isNumber(Number.MIN_VALUE); + * // => true + * + * _.isNumber(Infinity); + * // => true + * + * _.isNumber('3'); + * // => false + */ + function isNumber(value) { + return typeof value == 'number' || + (isObjectLike(value) && baseGetTag(value) == numberTag); + } + + /** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ + function isPlainObject(value) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; + } + + /** + * Checks if `value` is classified as a `RegExp` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + * @example + * + * _.isRegExp(/abc/); + * // => true + * + * _.isRegExp('/abc/'); + * // => false + */ + var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; + + /** + * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754 + * double precision number which isn't the result of a rounded unsafe integer. + * + * **Note:** This method is based on + * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`. + * @example + * + * _.isSafeInteger(3); + * // => true + * + * _.isSafeInteger(Number.MIN_VALUE); + * // => false + * + * _.isSafeInteger(Infinity); + * // => false + * + * _.isSafeInteger('3'); + * // => false + */ + function isSafeInteger(value) { + return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is classified as a `Set` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + * @example + * + * _.isSet(new Set); + * // => true + * + * _.isSet(new WeakSet); + * // => false + */ + var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; + + /** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ + function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); + } + + /** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ + function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); + } + + /** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ + var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + + /** + * Checks if `value` is `undefined`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + * @example + * + * _.isUndefined(void 0); + * // => true + * + * _.isUndefined(null); + * // => false + */ + function isUndefined(value) { + return value === undefined; + } + + /** + * Checks if `value` is classified as a `WeakMap` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a weak map, else `false`. + * @example + * + * _.isWeakMap(new WeakMap); + * // => true + * + * _.isWeakMap(new Map); + * // => false + */ + function isWeakMap(value) { + return isObjectLike(value) && getTag(value) == weakMapTag; + } + + /** + * Checks if `value` is classified as a `WeakSet` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a weak set, else `false`. + * @example + * + * _.isWeakSet(new WeakSet); + * // => true + * + * _.isWeakSet(new Set); + * // => false + */ + function isWeakSet(value) { + return isObjectLike(value) && baseGetTag(value) == weakSetTag; + } + + /** + * Checks if `value` is less than `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than `other`, + * else `false`. + * @see _.gt + * @example + * + * _.lt(1, 3); + * // => true + * + * _.lt(3, 3); + * // => false + * + * _.lt(3, 1); + * // => false + */ + var lt = createRelationalOperation(baseLt); + + /** + * Checks if `value` is less than or equal to `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than or equal to + * `other`, else `false`. + * @see _.gte + * @example + * + * _.lte(1, 3); + * // => true + * + * _.lte(3, 3); + * // => true + * + * _.lte(3, 1); + * // => false + */ + var lte = createRelationalOperation(function(value, other) { + return value <= other; + }); + + /** + * Converts `value` to an array. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {Array} Returns the converted array. + * @example + * + * _.toArray({ 'a': 1, 'b': 2 }); + * // => [1, 2] + * + * _.toArray('abc'); + * // => ['a', 'b', 'c'] + * + * _.toArray(1); + * // => [] + * + * _.toArray(null); + * // => [] + */ + function toArray(value) { + if (!value) { + return []; + } + if (isArrayLike(value)) { + return isString(value) ? stringToArray(value) : copyArray(value); + } + if (symIterator && value[symIterator]) { + return iteratorToArray(value[symIterator]()); + } + var tag = getTag(value), + func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); + + return func(value); + } + + /** + * Converts `value` to a finite number. + * + * @static + * @memberOf _ + * @since 4.12.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted number. + * @example + * + * _.toFinite(3.2); + * // => 3.2 + * + * _.toFinite(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toFinite(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toFinite('3.2'); + * // => 3.2 + */ + function toFinite(value) { + if (!value) { + return value === 0 ? value : 0; + } + value = toNumber(value); + if (value === INFINITY || value === -INFINITY) { + var sign = (value < 0 ? -1 : 1); + return sign * MAX_INTEGER; + } + return value === value ? value : 0; + } + + /** + * Converts `value` to an integer. + * + * **Note:** This method is loosely based on + * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toInteger(3.2); + * // => 3 + * + * _.toInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toInteger(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toInteger('3.2'); + * // => 3 + */ + function toInteger(value) { + var result = toFinite(value), + remainder = result % 1; + + return result === result ? (remainder ? result - remainder : result) : 0; + } + + /** + * Converts `value` to an integer suitable for use as the length of an + * array-like object. + * + * **Note:** This method is based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toLength(3.2); + * // => 3 + * + * _.toLength(Number.MIN_VALUE); + * // => 0 + * + * _.toLength(Infinity); + * // => 4294967295 + * + * _.toLength('3.2'); + * // => 3 + */ + function toLength(value) { + return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0; + } + + /** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ + function toNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject(other) ? (other + '') : other; + } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ''); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); + } + + /** + * Converts `value` to a plain object flattening inherited enumerable string + * keyed properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ + function toPlainObject(value) { + return copyObject(value, keysIn(value)); + } + + /** + * Converts `value` to a safe integer. A safe integer can be compared and + * represented correctly. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toSafeInteger(3.2); + * // => 3 + * + * _.toSafeInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toSafeInteger(Infinity); + * // => 9007199254740991 + * + * _.toSafeInteger('3.2'); + * // => 3 + */ + function toSafeInteger(value) { + return value + ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER) + : (value === 0 ? value : 0); + } + + /** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ + function toString(value) { + return value == null ? '' : baseToString(value); + } + + /*------------------------------------------------------------------------*/ + + /** + * Assigns own enumerable string keyed properties of source objects to the + * destination object. Source objects are applied from left to right. + * Subsequent sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object` and is loosely based on + * [`Object.assign`](https://mdn.io/Object/assign). + * + * @static + * @memberOf _ + * @since 0.10.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.assignIn + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * function Bar() { + * this.c = 3; + * } + * + * Foo.prototype.b = 2; + * Bar.prototype.d = 4; + * + * _.assign({ 'a': 0 }, new Foo, new Bar); + * // => { 'a': 1, 'c': 3 } + */ + var assign = createAssigner(function(object, source) { + if (isPrototype(source) || isArrayLike(source)) { + copyObject(source, keys(source), object); + return; + } + for (var key in source) { + if (hasOwnProperty.call(source, key)) { + assignValue(object, key, source[key]); + } + } + }); + + /** + * This method is like `_.assign` except that it iterates over own and + * inherited source properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias extend + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.assign + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * function Bar() { + * this.c = 3; + * } + * + * Foo.prototype.b = 2; + * Bar.prototype.d = 4; + * + * _.assignIn({ 'a': 0 }, new Foo, new Bar); + * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } + */ + var assignIn = createAssigner(function(object, source) { + copyObject(source, keysIn(source), object); + }); + + /** + * This method is like `_.assignIn` except that it accepts `customizer` + * which is invoked to produce the assigned values. If `customizer` returns + * `undefined`, assignment is handled by the method instead. The `customizer` + * is invoked with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias extendWith + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @see _.assignWith + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignInWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { + copyObject(source, keysIn(source), object, customizer); + }); + + /** + * This method is like `_.assign` except that it accepts `customizer` + * which is invoked to produce the assigned values. If `customizer` returns + * `undefined`, assignment is handled by the method instead. The `customizer` + * is invoked with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @see _.assignInWith + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var assignWith = createAssigner(function(object, source, srcIndex, customizer) { + copyObject(source, keys(source), object, customizer); + }); + + /** + * Creates an array of values corresponding to `paths` of `object`. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Array} Returns the picked values. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _.at(object, ['a[0].b.c', 'a[1]']); + * // => [3, 4] + */ + var at = flatRest(baseAt); + + /** + * Creates an object that inherits from the `prototype` object. If a + * `properties` object is given, its own enumerable string keyed properties + * are assigned to the created object. + * + * @static + * @memberOf _ + * @since 2.3.0 + * @category Object + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { + * 'constructor': Circle + * }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ + function create(prototype, properties) { + var result = baseCreate(prototype); + return properties == null ? result : baseAssign(result, properties); + } + + /** + * Assigns own and inherited enumerable string keyed properties of source + * objects to the destination object for all destination properties that + * resolve to `undefined`. Source objects are applied from left to right. + * Once a property is set, additional values of the same property are ignored. + * + * **Note:** This method mutates `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.defaultsDeep + * @example + * + * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var defaults = baseRest(function(object, sources) { + object = Object(object); + + var index = -1; + var length = sources.length; + var guard = length > 2 ? sources[2] : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + length = 1; + } + + while (++index < length) { + var source = sources[index]; + var props = keysIn(source); + var propsIndex = -1; + var propsLength = props.length; + + while (++propsIndex < propsLength) { + var key = props[propsIndex]; + var value = object[key]; + + if (value === undefined || + (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) { + object[key] = source[key]; + } + } + } + + return object; + }); + + /** + * This method is like `_.defaults` except that it recursively assigns + * default properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.10.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.defaults + * @example + * + * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); + * // => { 'a': { 'b': 2, 'c': 3 } } + */ + var defaultsDeep = baseRest(function(args) { + args.push(undefined, customDefaultsMerge); + return apply(mergeWith, undefined, args); + }); + + /** + * This method is like `_.find` except that it returns the key of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findKey(users, function(o) { return o.age < 40; }); + * // => 'barney' (iteration order is not guaranteed) + * + * // The `_.matches` iteratee shorthand. + * _.findKey(users, { 'age': 1, 'active': true }); + * // => 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findKey(users, 'active'); + * // => 'barney' + */ + function findKey(object, predicate) { + return baseFindKey(object, getIteratee(predicate, 3), baseForOwn); + } + + /** + * This method is like `_.findKey` except that it iterates over elements of + * a collection in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findLastKey(users, function(o) { return o.age < 40; }); + * // => returns 'pebbles' assuming `_.findKey` returns 'barney' + * + * // The `_.matches` iteratee shorthand. + * _.findLastKey(users, { 'age': 36, 'active': true }); + * // => 'barney' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findLastKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findLastKey(users, 'active'); + * // => 'pebbles' + */ + function findLastKey(object, predicate) { + return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight); + } + + /** + * Iterates over own and inherited enumerable string keyed properties of an + * object and invokes `iteratee` for each property. The iteratee is invoked + * with three arguments: (value, key, object). Iteratee functions may exit + * iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 0.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forInRight + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forIn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed). + */ + function forIn(object, iteratee) { + return object == null + ? object + : baseFor(object, getIteratee(iteratee, 3), keysIn); + } + + /** + * This method is like `_.forIn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forIn + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forInRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'. + */ + function forInRight(object, iteratee) { + return object == null + ? object + : baseForRight(object, getIteratee(iteratee, 3), keysIn); + } + + /** + * Iterates over own enumerable string keyed properties of an object and + * invokes `iteratee` for each property. The iteratee is invoked with three + * arguments: (value, key, object). Iteratee functions may exit iteration + * early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 0.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forOwnRight + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a' then 'b' (iteration order is not guaranteed). + */ + function forOwn(object, iteratee) { + return object && baseForOwn(object, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.forOwn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forOwn + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwnRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'. + */ + function forOwnRight(object, iteratee) { + return object && baseForOwnRight(object, getIteratee(iteratee, 3)); + } + + /** + * Creates an array of function property names from own enumerable properties + * of `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the function names. + * @see _.functionsIn + * @example + * + * function Foo() { + * this.a = _.constant('a'); + * this.b = _.constant('b'); + * } + * + * Foo.prototype.c = _.constant('c'); + * + * _.functions(new Foo); + * // => ['a', 'b'] + */ + function functions(object) { + return object == null ? [] : baseFunctions(object, keys(object)); + } + + /** + * Creates an array of function property names from own and inherited + * enumerable properties of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the function names. + * @see _.functions + * @example + * + * function Foo() { + * this.a = _.constant('a'); + * this.b = _.constant('b'); + * } + * + * Foo.prototype.c = _.constant('c'); + * + * _.functionsIn(new Foo); + * // => ['a', 'b', 'c'] + */ + function functionsIn(object) { + return object == null ? [] : baseFunctions(object, keysIn(object)); + } + + /** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ + function get(object, path, defaultValue) { + var result = object == null ? undefined : baseGet(object, path); + return result === undefined ? defaultValue : result; + } + + /** + * Checks if `path` is a direct property of `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = { 'a': { 'b': 2 } }; + * var other = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.has(object, 'a'); + * // => true + * + * _.has(object, 'a.b'); + * // => true + * + * _.has(object, ['a', 'b']); + * // => true + * + * _.has(other, 'a'); + * // => false + */ + function has(object, path) { + return object != null && hasPath(object, path, baseHas); + } + + /** + * Checks if `path` is a direct or inherited property of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.hasIn(object, 'a'); + * // => true + * + * _.hasIn(object, 'a.b'); + * // => true + * + * _.hasIn(object, ['a', 'b']); + * // => true + * + * _.hasIn(object, 'b'); + * // => false + */ + function hasIn(object, path) { + return object != null && hasPath(object, path, baseHasIn); + } + + /** + * Creates an object composed of the inverted keys and values of `object`. + * If `object` contains duplicate values, subsequent values overwrite + * property assignments of previous values. + * + * @static + * @memberOf _ + * @since 0.7.0 + * @category Object + * @param {Object} object The object to invert. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invert(object); + * // => { '1': 'c', '2': 'b' } + */ + var invert = createInverter(function(result, value, key) { + if (value != null && + typeof value.toString != 'function') { + value = nativeObjectToString.call(value); + } + + result[value] = key; + }, constant(identity)); + + /** + * This method is like `_.invert` except that the inverted object is generated + * from the results of running each element of `object` thru `iteratee`. The + * corresponding inverted value of each inverted key is an array of keys + * responsible for generating the inverted value. The iteratee is invoked + * with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.1.0 + * @category Object + * @param {Object} object The object to invert. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invertBy(object); + * // => { '1': ['a', 'c'], '2': ['b'] } + * + * _.invertBy(object, function(value) { + * return 'group' + value; + * }); + * // => { 'group1': ['a', 'c'], 'group2': ['b'] } + */ + var invertBy = createInverter(function(result, value, key) { + if (value != null && + typeof value.toString != 'function') { + value = nativeObjectToString.call(value); + } + + if (hasOwnProperty.call(result, value)) { + result[value].push(key); + } else { + result[value] = [key]; + } + }, getIteratee); + + /** + * Invokes the method at `path` of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {...*} [args] The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + * @example + * + * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] }; + * + * _.invoke(object, 'a[0].b.c.slice', 1, 3); + * // => [2, 3] + */ + var invoke = baseRest(baseInvoke); + + /** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ + function keys(object) { + return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); + } + + /** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ + function keysIn(object) { + return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); + } + + /** + * The opposite of `_.mapValues`; this method creates an object with the + * same values as `object` and keys generated by running each own enumerable + * string keyed property of `object` thru `iteratee`. The iteratee is invoked + * with three arguments: (value, key, object). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapValues + * @example + * + * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { + * return key + value; + * }); + * // => { 'a1': 1, 'b2': 2 } + */ + function mapKeys(object, iteratee) { + var result = {}; + iteratee = getIteratee(iteratee, 3); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, iteratee(value, key, object), value); + }); + return result; + } + + /** + * Creates an object with the same keys as `object` and values generated + * by running each own enumerable string keyed property of `object` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, key, object). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapKeys + * @example + * + * var users = { + * 'fred': { 'user': 'fred', 'age': 40 }, + * 'pebbles': { 'user': 'pebbles', 'age': 1 } + * }; + * + * _.mapValues(users, function(o) { return o.age; }); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + * + * // The `_.property` iteratee shorthand. + * _.mapValues(users, 'age'); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + */ + function mapValues(object, iteratee) { + var result = {}; + iteratee = getIteratee(iteratee, 3); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, key, iteratee(value, key, object)); + }); + return result; + } + + /** + * This method is like `_.assign` except that it recursively merges own and + * inherited enumerable string keyed properties of source objects into the + * destination object. Source properties that resolve to `undefined` are + * skipped if a destination value exists. Array and plain object properties + * are merged recursively. Other objects and value types are overridden by + * assignment. Source objects are applied from left to right. Subsequent + * sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var object = { + * 'a': [{ 'b': 2 }, { 'd': 4 }] + * }; + * + * var other = { + * 'a': [{ 'c': 3 }, { 'e': 5 }] + * }; + * + * _.merge(object, other); + * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } + */ + var merge = createAssigner(function(object, source, srcIndex) { + baseMerge(object, source, srcIndex); + }); + + /** + * This method is like `_.merge` except that it accepts `customizer` which + * is invoked to produce the merged values of the destination and source + * properties. If `customizer` returns `undefined`, merging is handled by the + * method instead. The `customizer` is invoked with six arguments: + * (objValue, srcValue, key, object, source, stack). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} customizer The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * function customizer(objValue, srcValue) { + * if (_.isArray(objValue)) { + * return objValue.concat(srcValue); + * } + * } + * + * var object = { 'a': [1], 'b': [2] }; + * var other = { 'a': [3], 'b': [4] }; + * + * _.mergeWith(object, other, customizer); + * // => { 'a': [1, 3], 'b': [2, 4] } + */ + var mergeWith = createAssigner(function(object, source, srcIndex, customizer) { + baseMerge(object, source, srcIndex, customizer); + }); + + /** + * The opposite of `_.pick`; this method creates an object composed of the + * own and inherited enumerable property paths of `object` that are not omitted. + * + * **Note:** This method is considerably slower than `_.pick`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to omit. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omit(object, ['a', 'c']); + * // => { 'b': '2' } + */ + var omit = flatRest(function(object, paths) { + var result = {}; + if (object == null) { + return result; + } + var isDeep = false; + paths = arrayMap(paths, function(path) { + path = castPath(path, object); + isDeep || (isDeep = path.length > 1); + return path; + }); + copyObject(object, getAllKeysIn(object), result); + if (isDeep) { + result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone); + } + var length = paths.length; + while (length--) { + baseUnset(result, paths[length]); + } + return result; + }); + + /** + * The opposite of `_.pickBy`; this method creates an object composed of + * the own and inherited enumerable string keyed properties of `object` that + * `predicate` doesn't return truthy for. The predicate is invoked with two + * arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omitBy(object, _.isNumber); + * // => { 'b': '2' } + */ + function omitBy(object, predicate) { + return pickBy(object, negate(getIteratee(predicate))); + } + + /** + * Creates an object composed of the picked `object` properties. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pick(object, ['a', 'c']); + * // => { 'a': 1, 'c': 3 } + */ + var pick = flatRest(function(object, paths) { + return object == null ? {} : basePick(object, paths); + }); + + /** + * Creates an object composed of the `object` properties `predicate` returns + * truthy for. The predicate is invoked with two arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pickBy(object, _.isNumber); + * // => { 'a': 1, 'c': 3 } + */ + function pickBy(object, predicate) { + if (object == null) { + return {}; + } + var props = arrayMap(getAllKeysIn(object), function(prop) { + return [prop]; + }); + predicate = getIteratee(predicate); + return basePickBy(object, props, function(value, path) { + return predicate(value, path[0]); + }); + } + + /** + * This method is like `_.get` except that if the resolved value is a + * function it's invoked with the `this` binding of its parent object and + * its result is returned. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to resolve. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; + * + * _.result(object, 'a[0].b.c1'); + * // => 3 + * + * _.result(object, 'a[0].b.c2'); + * // => 4 + * + * _.result(object, 'a[0].b.c3', 'default'); + * // => 'default' + * + * _.result(object, 'a[0].b.c3', _.constant('default')); + * // => 'default' + */ + function result(object, path, defaultValue) { + path = castPath(path, object); + + var index = -1, + length = path.length; + + // Ensure the loop is entered when path is empty. + if (!length) { + length = 1; + object = undefined; + } + while (++index < length) { + var value = object == null ? undefined : object[toKey(path[index])]; + if (value === undefined) { + index = length; + value = defaultValue; + } + object = isFunction(value) ? value.call(object) : value; + } + return object; + } + + /** + * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, + * it's created. Arrays are created for missing index properties while objects + * are created for all other missing properties. Use `_.setWith` to customize + * `path` creation. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @returns {Object} Returns `object`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.set(object, 'a[0].b.c', 4); + * console.log(object.a[0].b.c); + * // => 4 + * + * _.set(object, ['x', '0', 'y', 'z'], 5); + * console.log(object.x[0].y.z); + * // => 5 + */ + function set(object, path, value) { + return object == null ? object : baseSet(object, path, value); + } + + /** + * This method is like `_.set` except that it accepts `customizer` which is + * invoked to produce the objects of `path`. If `customizer` returns `undefined` + * path creation is handled by the method instead. The `customizer` is invoked + * with three arguments: (nsValue, key, nsObject). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * var object = {}; + * + * _.setWith(object, '[0][1]', 'a', Object); + * // => { '0': { '1': 'a' } } + */ + function setWith(object, path, value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return object == null ? object : baseSet(object, path, value, customizer); + } + + /** + * Creates an array of own enumerable string keyed-value pairs for `object` + * which can be consumed by `_.fromPairs`. If `object` is a map or set, its + * entries are returned. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias entries + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the key-value pairs. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.toPairs(new Foo); + * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) + */ + var toPairs = createToPairs(keys); + + /** + * Creates an array of own and inherited enumerable string keyed-value pairs + * for `object` which can be consumed by `_.fromPairs`. If `object` is a map + * or set, its entries are returned. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias entriesIn + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the key-value pairs. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.toPairsIn(new Foo); + * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed) + */ + var toPairsIn = createToPairs(keysIn); + + /** + * An alternative to `_.reduce`; this method transforms `object` to a new + * `accumulator` object which is the result of running each of its own + * enumerable string keyed properties thru `iteratee`, with each invocation + * potentially mutating the `accumulator` object. If `accumulator` is not + * provided, a new object with the same `[[Prototype]]` will be used. The + * iteratee is invoked with four arguments: (accumulator, value, key, object). + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 1.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The custom accumulator value. + * @returns {*} Returns the accumulated value. + * @example + * + * _.transform([2, 3, 4], function(result, n) { + * result.push(n *= n); + * return n % 2 == 0; + * }, []); + * // => [4, 9] + * + * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { + * (result[value] || (result[value] = [])).push(key); + * }, {}); + * // => { '1': ['a', 'c'], '2': ['b'] } + */ + function transform(object, iteratee, accumulator) { + var isArr = isArray(object), + isArrLike = isArr || isBuffer(object) || isTypedArray(object); + + iteratee = getIteratee(iteratee, 4); + if (accumulator == null) { + var Ctor = object && object.constructor; + if (isArrLike) { + accumulator = isArr ? new Ctor : []; + } + else if (isObject(object)) { + accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; + } + else { + accumulator = {}; + } + } + (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) { + return iteratee(accumulator, value, index, object); + }); + return accumulator; + } + + /** + * Removes the property at `path` of `object`. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 7 } }] }; + * _.unset(object, 'a[0].b.c'); + * // => true + * + * console.log(object); + * // => { 'a': [{ 'b': {} }] }; + * + * _.unset(object, ['a', '0', 'b', 'c']); + * // => true + * + * console.log(object); + * // => { 'a': [{ 'b': {} }] }; + */ + function unset(object, path) { + return object == null ? true : baseUnset(object, path); + } + + /** + * This method is like `_.set` except that accepts `updater` to produce the + * value to set. Use `_.updateWith` to customize `path` creation. The `updater` + * is invoked with one argument: (value). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {Function} updater The function to produce the updated value. + * @returns {Object} Returns `object`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.update(object, 'a[0].b.c', function(n) { return n * n; }); + * console.log(object.a[0].b.c); + * // => 9 + * + * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; }); + * console.log(object.x[0].y.z); + * // => 0 + */ + function update(object, path, updater) { + return object == null ? object : baseUpdate(object, path, castFunction(updater)); + } + + /** + * This method is like `_.update` except that it accepts `customizer` which is + * invoked to produce the objects of `path`. If `customizer` returns `undefined` + * path creation is handled by the method instead. The `customizer` is invoked + * with three arguments: (nsValue, key, nsObject). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {Function} updater The function to produce the updated value. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * var object = {}; + * + * _.updateWith(object, '[0][1]', _.constant('a'), Object); + * // => { '0': { '1': 'a' } } + */ + function updateWith(object, path, updater, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer); + } + + /** + * Creates an array of the own enumerable string keyed property values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.values(new Foo); + * // => [1, 2] (iteration order is not guaranteed) + * + * _.values('hi'); + * // => ['h', 'i'] + */ + function values(object) { + return object == null ? [] : baseValues(object, keys(object)); + } + + /** + * Creates an array of the own and inherited enumerable string keyed property + * values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.valuesIn(new Foo); + * // => [1, 2, 3] (iteration order is not guaranteed) + */ + function valuesIn(object) { + return object == null ? [] : baseValues(object, keysIn(object)); + } + + /*------------------------------------------------------------------------*/ + + /** + * Clamps `number` within the inclusive `lower` and `upper` bounds. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Number + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + * @example + * + * _.clamp(-10, -5, 5); + * // => -5 + * + * _.clamp(10, -5, 5); + * // => 5 + */ + function clamp(number, lower, upper) { + if (upper === undefined) { + upper = lower; + lower = undefined; + } + if (upper !== undefined) { + upper = toNumber(upper); + upper = upper === upper ? upper : 0; + } + if (lower !== undefined) { + lower = toNumber(lower); + lower = lower === lower ? lower : 0; + } + return baseClamp(toNumber(number), lower, upper); + } + + /** + * Checks if `n` is between `start` and up to, but not including, `end`. If + * `end` is not specified, it's set to `start` with `start` then set to `0`. + * If `start` is greater than `end` the params are swapped to support + * negative ranges. + * + * @static + * @memberOf _ + * @since 3.3.0 + * @category Number + * @param {number} number The number to check. + * @param {number} [start=0] The start of the range. + * @param {number} end The end of the range. + * @returns {boolean} Returns `true` if `number` is in the range, else `false`. + * @see _.range, _.rangeRight + * @example + * + * _.inRange(3, 2, 4); + * // => true + * + * _.inRange(4, 8); + * // => true + * + * _.inRange(4, 2); + * // => false + * + * _.inRange(2, 2); + * // => false + * + * _.inRange(1.2, 2); + * // => true + * + * _.inRange(5.2, 4); + * // => false + * + * _.inRange(-3, -2, -6); + * // => true + */ + function inRange(number, start, end) { + start = toFinite(start); + if (end === undefined) { + end = start; + start = 0; + } else { + end = toFinite(end); + } + number = toNumber(number); + return baseInRange(number, start, end); + } + + /** + * Produces a random number between the inclusive `lower` and `upper` bounds. + * If only one argument is provided a number between `0` and the given number + * is returned. If `floating` is `true`, or either `lower` or `upper` are + * floats, a floating-point number is returned instead of an integer. + * + * **Note:** JavaScript follows the IEEE-754 standard for resolving + * floating-point values which can produce unexpected results. + * + * @static + * @memberOf _ + * @since 0.7.0 + * @category Number + * @param {number} [lower=0] The lower bound. + * @param {number} [upper=1] The upper bound. + * @param {boolean} [floating] Specify returning a floating-point number. + * @returns {number} Returns the random number. + * @example + * + * _.random(0, 5); + * // => an integer between 0 and 5 + * + * _.random(5); + * // => also an integer between 0 and 5 + * + * _.random(5, true); + * // => a floating-point number between 0 and 5 + * + * _.random(1.2, 5.2); + * // => a floating-point number between 1.2 and 5.2 + */ + function random(lower, upper, floating) { + if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { + upper = floating = undefined; + } + if (floating === undefined) { + if (typeof upper == 'boolean') { + floating = upper; + upper = undefined; + } + else if (typeof lower == 'boolean') { + floating = lower; + lower = undefined; + } + } + if (lower === undefined && upper === undefined) { + lower = 0; + upper = 1; + } + else { + lower = toFinite(lower); + if (upper === undefined) { + upper = lower; + lower = 0; + } else { + upper = toFinite(upper); + } + } + if (lower > upper) { + var temp = lower; + lower = upper; + upper = temp; + } + if (floating || lower % 1 || upper % 1) { + var rand = nativeRandom(); + return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); + } + return baseRandom(lower, upper); + } + + /*------------------------------------------------------------------------*/ + + /** + * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the camel cased string. + * @example + * + * _.camelCase('Foo Bar'); + * // => 'fooBar' + * + * _.camelCase('--foo-bar--'); + * // => 'fooBar' + * + * _.camelCase('__FOO_BAR__'); + * // => 'fooBar' + */ + var camelCase = createCompounder(function(result, word, index) { + word = word.toLowerCase(); + return result + (index ? capitalize(word) : word); + }); + + /** + * Converts the first character of `string` to upper case and the remaining + * to lower case. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to capitalize. + * @returns {string} Returns the capitalized string. + * @example + * + * _.capitalize('FRED'); + * // => 'Fred' + */ + function capitalize(string) { + return upperFirst(toString(string).toLowerCase()); + } + + /** + * Deburrs `string` by converting + * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) + * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A) + * letters to basic Latin letters and removing + * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to deburr. + * @returns {string} Returns the deburred string. + * @example + * + * _.deburr('déjà vu'); + * // => 'deja vu' + */ + function deburr(string) { + string = toString(string); + return string && string.replace(reLatin, deburrLetter).replace(reComboMark, ''); + } + + /** + * Checks if `string` ends with the given target string. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to inspect. + * @param {string} [target] The string to search for. + * @param {number} [position=string.length] The position to search up to. + * @returns {boolean} Returns `true` if `string` ends with `target`, + * else `false`. + * @example + * + * _.endsWith('abc', 'c'); + * // => true + * + * _.endsWith('abc', 'b'); + * // => false + * + * _.endsWith('abc', 'b', 2); + * // => true + */ + function endsWith(string, target, position) { + string = toString(string); + target = baseToString(target); + + var length = string.length; + position = position === undefined + ? length + : baseClamp(toInteger(position), 0, length); + + var end = position; + position -= target.length; + return position >= 0 && string.slice(position, end) == target; + } + + /** + * Converts the characters "&", "<", ">", '"', and "'" in `string` to their + * corresponding HTML entities. + * + * **Note:** No other characters are escaped. To escape additional + * characters use a third-party library like [_he_](https://mths.be/he). + * + * Though the ">" character is escaped for symmetry, characters like + * ">" and "/" don't need escaping in HTML and have no special meaning + * unless they're part of a tag or unquoted attribute value. See + * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) + * (under "semi-related fun fact") for more details. + * + * When working with HTML you should always + * [quote attribute values](http://wonko.com/post/html-escaping) to reduce + * XSS vectors. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escape('fred, barney, & pebbles'); + * // => 'fred, barney, & pebbles' + */ + function escape(string) { + string = toString(string); + return (string && reHasUnescapedHtml.test(string)) + ? string.replace(reUnescapedHtml, escapeHtmlChar) + : string; + } + + /** + * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", + * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escapeRegExp('[lodash](https://lodash.com/)'); + * // => '\[lodash\]\(https://lodash\.com/\)' + */ + function escapeRegExp(string) { + string = toString(string); + return (string && reHasRegExpChar.test(string)) + ? string.replace(reRegExpChar, '\\$&') + : string; + } + + /** + * Converts `string` to + * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the kebab cased string. + * @example + * + * _.kebabCase('Foo Bar'); + * // => 'foo-bar' + * + * _.kebabCase('fooBar'); + * // => 'foo-bar' + * + * _.kebabCase('__FOO_BAR__'); + * // => 'foo-bar' + */ + var kebabCase = createCompounder(function(result, word, index) { + return result + (index ? '-' : '') + word.toLowerCase(); + }); + + /** + * Converts `string`, as space separated words, to lower case. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the lower cased string. + * @example + * + * _.lowerCase('--Foo-Bar--'); + * // => 'foo bar' + * + * _.lowerCase('fooBar'); + * // => 'foo bar' + * + * _.lowerCase('__FOO_BAR__'); + * // => 'foo bar' + */ + var lowerCase = createCompounder(function(result, word, index) { + return result + (index ? ' ' : '') + word.toLowerCase(); + }); + + /** + * Converts the first character of `string` to lower case. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.lowerFirst('Fred'); + * // => 'fred' + * + * _.lowerFirst('FRED'); + * // => 'fRED' + */ + var lowerFirst = createCaseFirst('toLowerCase'); + + /** + * Pads `string` on the left and right sides if it's shorter than `length`. + * Padding characters are truncated if they can't be evenly divided by `length`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.pad('abc', 8); + * // => ' abc ' + * + * _.pad('abc', 8, '_-'); + * // => '_-abc_-_' + * + * _.pad('abc', 3); + * // => 'abc' + */ + function pad(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + if (!length || strLength >= length) { + return string; + } + var mid = (length - strLength) / 2; + return ( + createPadding(nativeFloor(mid), chars) + + string + + createPadding(nativeCeil(mid), chars) + ); + } + + /** + * Pads `string` on the right side if it's shorter than `length`. Padding + * characters are truncated if they exceed `length`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padEnd('abc', 6); + * // => 'abc ' + * + * _.padEnd('abc', 6, '_-'); + * // => 'abc_-_' + * + * _.padEnd('abc', 3); + * // => 'abc' + */ + function padEnd(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + return (length && strLength < length) + ? (string + createPadding(length - strLength, chars)) + : string; + } + + /** + * Pads `string` on the left side if it's shorter than `length`. Padding + * characters are truncated if they exceed `length`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padStart('abc', 6); + * // => ' abc' + * + * _.padStart('abc', 6, '_-'); + * // => '_-_abc' + * + * _.padStart('abc', 3); + * // => 'abc' + */ + function padStart(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + return (length && strLength < length) + ? (createPadding(length - strLength, chars) + string) + : string; + } + + /** + * Converts `string` to an integer of the specified radix. If `radix` is + * `undefined` or `0`, a `radix` of `10` is used unless `value` is a + * hexadecimal, in which case a `radix` of `16` is used. + * + * **Note:** This method aligns with the + * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category String + * @param {string} string The string to convert. + * @param {number} [radix=10] The radix to interpret `value` by. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {number} Returns the converted integer. + * @example + * + * _.parseInt('08'); + * // => 8 + * + * _.map(['6', '08', '10'], _.parseInt); + * // => [6, 8, 10] + */ + function parseInt(string, radix, guard) { + if (guard || radix == null) { + radix = 0; + } else if (radix) { + radix = +radix; + } + return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0); + } + + /** + * Repeats the given string `n` times. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to repeat. + * @param {number} [n=1] The number of times to repeat the string. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {string} Returns the repeated string. + * @example + * + * _.repeat('*', 3); + * // => '***' + * + * _.repeat('abc', 2); + * // => 'abcabc' + * + * _.repeat('abc', 0); + * // => '' + */ + function repeat(string, n, guard) { + if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) { + n = 1; + } else { + n = toInteger(n); + } + return baseRepeat(toString(string), n); + } + + /** + * Replaces matches for `pattern` in `string` with `replacement`. + * + * **Note:** This method is based on + * [`String#replace`](https://mdn.io/String/replace). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to modify. + * @param {RegExp|string} pattern The pattern to replace. + * @param {Function|string} replacement The match replacement. + * @returns {string} Returns the modified string. + * @example + * + * _.replace('Hi Fred', 'Fred', 'Barney'); + * // => 'Hi Barney' + */ + function replace() { + var args = arguments, + string = toString(args[0]); + + return args.length < 3 ? string : string.replace(args[1], args[2]); + } + + /** + * Converts `string` to + * [snake case](https://en.wikipedia.org/wiki/Snake_case). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the snake cased string. + * @example + * + * _.snakeCase('Foo Bar'); + * // => 'foo_bar' + * + * _.snakeCase('fooBar'); + * // => 'foo_bar' + * + * _.snakeCase('--FOO-BAR--'); + * // => 'foo_bar' + */ + var snakeCase = createCompounder(function(result, word, index) { + return result + (index ? '_' : '') + word.toLowerCase(); + }); + + /** + * Splits `string` by `separator`. + * + * **Note:** This method is based on + * [`String#split`](https://mdn.io/String/split). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to split. + * @param {RegExp|string} separator The separator pattern to split by. + * @param {number} [limit] The length to truncate results to. + * @returns {Array} Returns the string segments. + * @example + * + * _.split('a-b-c', '-', 2); + * // => ['a', 'b'] + */ + function split(string, separator, limit) { + if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) { + separator = limit = undefined; + } + limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0; + if (!limit) { + return []; + } + string = toString(string); + if (string && ( + typeof separator == 'string' || + (separator != null && !isRegExp(separator)) + )) { + separator = baseToString(separator); + if (!separator && hasUnicode(string)) { + return castSlice(stringToArray(string), 0, limit); + } + } + return string.split(separator, limit); + } + + /** + * Converts `string` to + * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). + * + * @static + * @memberOf _ + * @since 3.1.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the start cased string. + * @example + * + * _.startCase('--foo-bar--'); + * // => 'Foo Bar' + * + * _.startCase('fooBar'); + * // => 'Foo Bar' + * + * _.startCase('__FOO_BAR__'); + * // => 'FOO BAR' + */ + var startCase = createCompounder(function(result, word, index) { + return result + (index ? ' ' : '') + upperFirst(word); + }); + + /** + * Checks if `string` starts with the given target string. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to inspect. + * @param {string} [target] The string to search for. + * @param {number} [position=0] The position to search from. + * @returns {boolean} Returns `true` if `string` starts with `target`, + * else `false`. + * @example + * + * _.startsWith('abc', 'a'); + * // => true + * + * _.startsWith('abc', 'b'); + * // => false + * + * _.startsWith('abc', 'b', 1); + * // => true + */ + function startsWith(string, target, position) { + string = toString(string); + position = position == null + ? 0 + : baseClamp(toInteger(position), 0, string.length); + + target = baseToString(target); + return string.slice(position, position + target.length) == target; + } + + /** + * Creates a compiled template function that can interpolate data properties + * in "interpolate" delimiters, HTML-escape interpolated data properties in + * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data + * properties may be accessed as free variables in the template. If a setting + * object is given, it takes precedence over `_.templateSettings` values. + * + * **Note:** In the development build `_.template` utilizes + * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) + * for easier debugging. + * + * For more information on precompiling templates see + * [lodash's custom builds documentation](https://lodash.com/custom-builds). + * + * For more information on Chrome extension sandboxes see + * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category String + * @param {string} [string=''] The template string. + * @param {Object} [options={}] The options object. + * @param {RegExp} [options.escape=_.templateSettings.escape] + * The HTML "escape" delimiter. + * @param {RegExp} [options.evaluate=_.templateSettings.evaluate] + * The "evaluate" delimiter. + * @param {Object} [options.imports=_.templateSettings.imports] + * An object to import into the template as free variables. + * @param {RegExp} [options.interpolate=_.templateSettings.interpolate] + * The "interpolate" delimiter. + * @param {string} [options.sourceURL='lodash.templateSources[n]'] + * The sourceURL of the compiled template. + * @param {string} [options.variable='obj'] + * The data object variable name. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the compiled template function. + * @example + * + * // Use the "interpolate" delimiter to create a compiled template. + * var compiled = _.template('hello <%= user %>!'); + * compiled({ 'user': 'fred' }); + * // => 'hello fred!' + * + * // Use the HTML "escape" delimiter to escape data property values. + * var compiled = _.template('<%- value %>'); + * compiled({ 'value': '